<# .SYNOPSIS Define OOBE Deploy Tasks .DESCRIPTION oobe.complianceag.osdcloud.ch .NOTES Version: 0.1 Creation Date: 22.04.2024 Author: Akos Bakos Company: SmartCon GmbH Contact: akos.bakos@smartcon.ch Copyright (c) 2024 SmartCon GmbH HISTORY: Date By Comments ---------- --- ---------------------------------------------------------- 22.04.2024 Akos Bakos Script created 23.04.2024 Akos Bakos Added helper functions 01.05.2024 Akos Bakos Change the Windows Activation to use the new method Add 'Driver update process' Add 'Remove DevHome & Outlook NEW process' Add 'Disable PowerShell 2.0 process' Add 'Stop Start menu from opening on first logon' Add 'Remove Microsoft Quick Assist process' Add 'OEM Branding process' 27.04.2025 Akos Bakos If VMWare, skip the OS activation process 05.05.2025 Akos Bakos Added VMware Tools and Omnissa Horizon Agent installation 18.09.2025 Akos Bakos Added smarter internet connectivity check 04.11.2025 Akos Bakos Added Download CMTrace process #> #region Helper Functions function Write-DarkGrayDate { [CmdletBinding()] param ( [Parameter(Position = 0)] [System.String] $Message ) if ($Message) { Write-Host -ForegroundColor DarkGray "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) $Message" } else { Write-Host -ForegroundColor DarkGray "$((Get-Date).ToString('yyyy-MM-dd-HHmmss')) " -NoNewline } } function Write-DarkGrayHost { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [System.String] $Message ) Write-Host -ForegroundColor DarkGray $Message } function Write-DarkGrayLine { [CmdletBinding()] param () Write-Host -ForegroundColor DarkGray "=========================================================================" } function Write-SectionHeader { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [System.String] $Message ) Write-DarkGrayLine Write-DarkGrayDate Write-Host -ForegroundColor Cyan $Message } function Write-DarkGrayHost { [CmdletBinding()] param ( [Parameter(Position = 0)] [System.String] $Message = 'Success!' ) Write-DarkGrayDate Write-Host -ForegroundColor Green $Message } #endregion $Title = "OOBE Tasks" $host.UI.RawUI.WindowTitle = $Title [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 [System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials $env:APPDATA = "C:\Windows\System32\Config\SystemProfile\AppData\Roaming" $env:LOCALAPPDATA = "C:\Windows\System32\Config\SystemProfile\AppData\Local" $Env:PSModulePath = $env:PSModulePath + ";C:\Program Files\WindowsPowerShell\Scripts" $env:Path = $env:Path + ";C:\Program Files\WindowsPowerShell\Scripts" $Global:Transcript = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Start-OOBEDeploy.log" Start-Transcript -Path (Join-Path "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\OSD\" $Global:Transcript) -ErrorAction Ignore | Out-Null if ((Get-ExecutionPolicy) -ne 'Bypass') { Write-DarkGrayHost "Set-ExecutionPolicy Bypass -Force" Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force } #region Driver update process function Ensure-UgreenRealtekUsb2p5GbeDriver { [CmdletBinding()] param( [string]$DriverRoot = "C:\OSDCloud\Drivers\UGreen", [switch]$RestartAdapter, [switch]$RenewDhcp ) Write-Host "Ensuring Realtek Gaming USB 2.5GbE (UGREEN) driver from: $DriverRoot" -ForegroundColor Cyan if (-not (Test-Path $DriverRoot)) { Write-Warning "Driver source not found: $DriverRoot" return $false } # Stage and install all matching INF files $infFiles = Get-ChildItem -Path $DriverRoot -Filter *.inf -Recurse -ErrorAction SilentlyContinue if (-not $infFiles) { Write-Warning "No INF files found under '$DriverRoot'" return $false } $installedAny = $false foreach ($inf in $infFiles) { try { pnputil.exe /add-driver "`"$($inf.FullName)`"" /install /subdirs | Out-Null $installedAny = $true } catch { Write-Host "Failed to add driver '$($inf.Name)': $($_.Exception.Message)" -ForegroundColor Yellow } } try { pnputil.exe /scan-devices | Out-Null } catch {} Start-Sleep -Seconds 5 # Detect Realtek/UGREEN 2.5GbE adapter $adapter = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.InterfaceDescription -match 'Realtek.*2\.5G' -or $_.InterfaceDescription -match 'RTL8156' -or $_.InterfaceDescription -match 'UGREEN' -or $_.Name -match 'Realtek|UGREEN' } | Select-Object -First 1 if ($adapter -and $RestartAdapter) { try { Disable-NetAdapter -Name $adapter.Name -Confirm:$false -ErrorAction Stop | Out-Null Start-Sleep -Seconds 2 Enable-NetAdapter -Name $adapter.Name -Confirm:$false -ErrorAction Stop | Out-Null } catch { Write-Warning "Failed to bounce adapter $($adapter.Name): $($_.Exception.Message)" } if ($RenewDhcp) { try { Start-Process "$env:SystemRoot\System32\ipconfig.exe" -ArgumentList "/renew" -WindowStyle Hidden -Wait } catch {} } Start-Sleep -Seconds 3 } $isUp = $false if ($adapter) { $refreshed = Get-NetAdapter -Name $adapter.Name -ErrorAction SilentlyContinue $isUp = $refreshed.Status -eq 'Up' } else { # Re-query in case it appeared after install $isUp = (Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.InterfaceDescription -match 'Realtek.*2\.5G' -or $_.InterfaceDescription -match 'RTL8156' -or $_.InterfaceDescription -match 'UGREEN' } | Where-Object Status -EQ 'Up') -ne $null } if ($isUp) { Write-Host "UGREEN/Realtek 2.5GbE adapter operational." -ForegroundColor Green return $true } else { Write-Warning "Adapter not up yet. Driver install attempted: $installedAny" return $installedAny } } #Ensure-UgreenRealtekUsb2p5GbeDriver -RestartAdapter -RenewDhcp #endregion #region Check Internet Connection #================================================= Write-SectionHeader "Check Internet Connection" #================================================= $maxAttempts = 30 $internetConnected = $false # Prefer endpoints required by this script/workflow $tests = @( @{ Type='Http'; Uri='http://www.msftconnecttest.com/connecttest.txt'; Expect='Microsoft Connect Test' }, # NCSI @{ Type='Http'; Uri='https://www.powershellgallery.com/api/v2'; ExpectStatus=200 }, # PSGallery @{ Type='Dns'; Name='api.nuget.org' }, # NuGet DNS @{ Type='Tcp'; Host='download.windowsupdate.com'; Port=443 } # WU TCP ) function Test-NetworkTarget { param([hashtable]$t) try { switch ($t.Type) { 'Http' { $resp = Invoke-WebRequest -Uri $t.Uri -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop if ($t.ContainsKey('Expect') -and $resp.Content -like "*$($t.Expect)*") { return $true } if ($t.ContainsKey('ExpectStatus') -and [int]$resp.StatusCode -eq [int]$t.ExpectStatus) { return $true } return $false } 'Tcp' { $r = Test-NetConnection -ComputerName $t.Host -Port $t.Port -WarningAction SilentlyContinue return [bool]$r.TcpTestSucceeded } 'Dns' { Resolve-DnsName -Name $t.Name -ErrorAction Stop | Out-Null return $true } } } catch { return $false } } function Restart-PrimaryNetAdapter { [CmdletBinding()] param( [int]$Retry = 2, [switch]$RenewDhcp ) # Pick adapter used for default IPv4 route $route = Get-NetRoute -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue | Sort-Object -Property RouteMetric, InterfaceMetric | Select-Object -First 1 $adapter = $null if ($route) { $adapter = Get-NetAdapter -InterfaceIndex $route.InterfaceIndex -ErrorAction SilentlyContinue } # Fallback: best physical, up adapter if (-not $adapter) { $adapter = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -in 'Up','Dormant' } | Sort-Object -Property ifIndex | Select-Object -First 1 } if (-not $adapter) { Write-Host "No suitable adapter found to restart." -ForegroundColor Yellow; return $false } # Avoid bouncing VPN/virtual/loopback/etc. $skipPatterns = 'Hyper-V|VMware|Virtual|Bluetooth|Loopback|TAP|TUN|WireGuard|AnyConnect|Fortinet|Juniper|ZeroTier|Npcap|WAN Miniport' if ($adapter.InterfaceDescription -match $skipPatterns) { Write-Host "Primary adapter appears virtual/VPN ($($adapter.InterfaceDescription)). Skipping restart." -ForegroundColor Yellow return $false } Write-Host "Restarting adapter: $($adapter.Name) [$($adapter.InterfaceDescription)]" -ForegroundColor Yellow $success = $false for ($i=0; $i -le $Retry -and -not $success; $i++) { try { Disable-NetAdapter -Name $adapter.Name -Confirm:$false -ErrorAction Stop | Out-Null Start-Sleep -Seconds 2 Enable-NetAdapter -Name $adapter.Name -Confirm:$false -ErrorAction Stop | Out-Null # Wait for link $wait = 0 do { Start-Sleep -Seconds 1 $wait++ $adapter = Get-NetAdapter -Name $adapter.Name -ErrorAction SilentlyContinue } while ($adapter.Status -notin @('Up','Dormant') -and $wait -lt 20) if ($RenewDhcp) { Start-Process -FilePath "$env:SystemRoot\System32\ipconfig.exe" -ArgumentList "/renew" -WindowStyle Hidden -Wait } $success = $adapter.Status -in @('Up','Dormant') } catch { Write-Host "Adapter restart attempt $($i+1) failed: $($_.Exception.Message)" -ForegroundColor Yellow } } return $success } for ($attempt = 1; $attempt -le $maxAttempts -and -not $internetConnected; $attempt++) { Write-DarkGrayHost "Checking internet connectivity (Attempt $attempt of $maxAttempts)" foreach ($t in $tests) { $label = if ($t.Type -eq 'Http') { $t.Uri } elseif ($t.Type -eq 'Tcp') { "$($t.Host):$($t.Port)" } else { $t.Name } if (Test-NetworkTarget $t) { Write-DarkGrayHost "Connectivity OK via $($t.Type): $label" $internetConnected = $true break } else { Write-DarkGrayHost "No response from $($t.Type): $label" } } if (-not $internetConnected -and $attempt -eq 3) { # After a few failed tries, bounce the adapter once Write-Host "No internet detected. Attempting to restart the primary network adapter..." -ForegroundColor Yellow $restarted = Restart-PrimaryNetAdapter -Retry 2 -RenewDhcp if ($restarted) { Write-Host "Adapter restarted. Re-checking connectivity..." -ForegroundColor Cyan # Quick re-check loop for ($j=1; $j -le 10 -and -not $internetConnected; $j++) { foreach ($t in $tests) { if (Test-NetworkTarget $t) { $internetConnected = $true; break } } if (-not $internetConnected) { Start-Sleep -Seconds 1 } } } else { Write-Host "Adapter restart skipped or failed." -ForegroundColor Yellow } } if (-not $internetConnected) { Start-Sleep -Seconds 1 } } if (-not $internetConnected) { Write-Host -ForegroundColor Yellow "Still no internet. Continuing; online steps may be skipped." } #endregion #Read-Host -Prompt "Stopping for further troubleshootings. Press Enter to continue..." #region Ensure PSGallery #================================================= Write-SectionHeader "Ensure PSGallery" #================================================= function Ensure-PSGallery { [CmdletBinding()] param() [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # NuGet provider if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) { try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null } catch { Write-Warning "NuGet install failed: $($_.Exception.Message)" } } # PowerShellGet module (baseline) if (-not (Get-Module -ListAvailable PowerShellGet)) { try { Install-Module PowerShellGet -MinimumVersion 2.2.5 -Force -AllowClobber -Scope AllUsers } catch {} } $repo = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue if ($repo -and ($repo.SourceLocation -notlike "https://www.powershellgallery.com/*")) { Write-Warning "PSGallery entry looks corrupt. Resetting..." try { Unregister-PSRepository -Name PSGallery -ErrorAction SilentlyContinue } catch {} $repo = $null } if (-not $repo) { # Cleanup stale registry entries (silent) Get-ChildItem HKLM:\SOFTWARE\Microsoft\PowerShell\PowerShellGet\RegisteredRepositories -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -eq 'PSGallery' } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Get-ChildItem HKCU:\SOFTWARE\Microsoft\PowerShell\PowerShellGet\RegisteredRepositories -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -eq 'PSGallery' } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue # Prefer -Default only if supported $hasDefaultParam = (Get-Command Register-PSRepository -ErrorAction SilentlyContinue).Parameters.ContainsKey('Default') try { if ($hasDefaultParam) { Register-PSRepository -Default -ErrorAction Stop } else { Register-PSRepository -Name PSGallery ` -SourceLocation "https://www.powershellgallery.com/api/v2" ` -ScriptSourceLocation "https://www.powershellgallery.com/api/v2" ` -InstallationPolicy Trusted -ErrorAction Stop } } catch { Write-Warning "Registration failed: $($_.Exception.Message)" } $repo = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue } if ($repo) { if ($repo.InstallationPolicy -ne 'Trusted') { try { Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction Stop } catch {} } Write-DarkGrayHost "[+] PSGallery OK" } else { Write-Warning "PSGallery unavailable. Check proxy / SSL inspection / connectivity." } } Ensure-PSGallery #endregion #region InstallModuleOSD function InstallModuleOSD { [CmdletBinding()] param () $PSModuleName = 'OSD' $InstalledModule = Get-Module -Name $PSModuleName -ListAvailable -ErrorAction Ignore | Sort-Object Version -Descending | Select-Object -First 1 $GalleryPSModule = Find-Module -Name $PSModuleName -ErrorAction Ignore -WarningAction Ignore if ($GalleryPSModule) { if (($GalleryPSModule.Version -as [version]) -gt ($InstalledModule.Version -as [version])) { Write-DarkGrayHost "[-] Install-Module $PSModuleName $($GalleryPSModule.Version)" Install-Module $PSModuleName -Scope AllUsers -Force -SkipPublisherCheck Import-Module $PSModuleName -Force } } $InstalledModule = Get-Module -Name $PSModuleName -ListAvailable -ErrorAction Ignore | Sort-Object Version -Descending | Select-Object -First 1 if ($GalleryPSModule) { if (($InstalledModule.Version -as [version]) -ge ($GalleryPSModule.Version -as [version])) { Write-DarkGrayHost "[+] $PSModuleName $($GalleryPSModule.Version)" } } } InstallModuleOSD #endregion #region Product activation #================================================= Write-SectionHeader "Windows Activation" #================================================= $host.ui.RawUI.WindowTitle = "Windows Activation" # Check if system is running on VMware $isVMware = $false try { $computerSystem = Get-WmiObject -Class Win32_ComputerSystem -ErrorAction Stop if ($computerSystem.Manufacturer -like "*VMware*") { $isVMware = $true Write-DarkGrayHost "System detected as running on VMware" } else { Write-DarkGrayHost "System not detected as VMware - proceeding with embedded key activation" } } catch { Write-Host -ForegroundColor Yellow "Could not determine if system is running on VMware: $($_.Exception.Message)" # Assume not VMware in case of error } # Activation logic based on environment if ($isVMware) { # VMware-specific activation Write-DarkGrayHost "Applying MAK key for VMware environment" $Key = "HW2BB-NK28J-YMPWF-62Q7D-C372F" # Store this securely in production Write-DarkGrayHost "Installing MAK product key" & cscript.exe "$env:windir\system32\slmgr.vbs" /ipk "$Key" | Out-Null Start-Sleep -Seconds 3 Write-DarkGrayHost "Activating product key" & cscript.exe "$env:windir\system32\slmgr.vbs" /ato | Out-Null } else { # Physical hardware - try embedded key $embeddedKey = (Get-WmiObject -Class SoftwareLicensingService).OA3xOriginalProductKey if ($embeddedKey) { Write-DarkGrayHost "Found embedded product key" Write-DarkGrayHost "Installing embedded product key" & cscript.exe "$env:windir\system32\slmgr.vbs" /ipk "$embeddedKey" | Out-Null Start-Sleep -Seconds 3 Write-DarkGrayHost "Activating embedded product key" & cscript.exe "$env:windir\system32\slmgr.vbs" /ato | Out-Null } else { Write-Host -ForegroundColor Yellow "No embedded product key found on this system" } } # Verify activation status after attempt Start-Sleep -Seconds 5 try { $activationStatus = Get-CimInstance -ClassName SoftwareLicensingProduct | Where-Object { $_.PartialProductKey -ne $null -and $_.Name -like "*Windows*" } | Select-Object -ExpandProperty LicenseStatus if ($activationStatus -eq 1) { Write-DarkGrayHost "Windows activation successful!" } else { Write-Host -ForegroundColor Yellow "Windows may not be properly activated. Status code: $activationStatus" } } catch { Write-Host -ForegroundColor Yellow "Could not verify activation status: $($_.Exception.Message)" } #endregion #region NetFx3 #================================================= Write-SectionHeader "Install NetFX3 - it can take up to 10 minutes" #================================================= $Title = 'Installing AddNetFX3' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) $AddWindowsCapability = Get-MyWindowsCapability -Match 'NetFX' -Detail foreach ($Item in $AddWindowsCapability) { if ($Item.State -ne 'Install') { Write-DarkGrayHost "$($Item.DisplayName)" $Item | Add-WindowsCapability -Online -ErrorAction Ignore | Out-Null } else { Write-DarkGrayHost "$($Item.DisplayName)" } } #endregion #region Remove-Appx #================================================= Write-SectionHeader "Remove-Appx" #================================================= $Title = 'Remove Appx' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) $Global:Transcript = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-Remove_AppXs.log" Start-Transcript -Path (Join-Path "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\OSD\" $Global:Transcript) -ErrorAction Ignore | Out-Null #Log Function function Write-LogEntry { param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Value, [parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$FileName = "AppXRemoval.log", [switch]$Stamp ) #Build Log File appending System Date/Time to output $LogFile = Join-Path -Path $env:SystemRoot -ChildPath $("Temp\$FileName") $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), " ", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) $Date = (Get-Date -Format "MM-dd-yyyy") If ($Stamp) { $LogText = "<$($Value)> " } else { $LogText = "$($Value)" } Try { Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFile -ErrorAction Stop } Catch [System.Exception] { Write-Warning -Message "Unable to add log entry to $LogFile.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" } } #Function to Remove AppxProvisionedPackage Function Remove-AppxProvisionedPackageCustom { # Attempt to remove AppxProvisioningPackage if (!([string]::IsNullOrEmpty($BlackListedApp))) { try { # Get Package Name $AppProvisioningPackageName = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $BlackListedApp } | Select-Object -ExpandProperty PackageName -First 1 Write-Host "$($BlackListedApp) found. Attempting removal ... " -NoNewline Write-LogEntry -Value "$($BlackListedApp) found. Attempting removal ... " # Attempt removeal $RemoveAppx = Remove-AppxProvisionedPackage -PackageName $AppProvisioningPackageName -Online -AllUsers #Re-check existence $AppProvisioningPackageNameReCheck = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $BlackListedApp } | Select-Object -ExpandProperty PackageName -First 1 If ([string]::IsNullOrEmpty($AppProvisioningPackageNameReCheck) -and ($RemoveAppx.Online -eq $true)) { Write-Host @CheckIcon Write-Host " (Removed)" Write-LogEntry -Value "$($BlackListedApp) removed" } } catch [System.Exception] { Write-Host " (Failed)" Write-LogEntry -Value "Failed to remove $($BlackListedApp)" } } } Write-LogEntry -Value "##################################" Write-LogEntry -Stamp -Value "Remove-Appx Started" Write-LogEntry -Value "##################################" #OS Check $OS = (Get-CimInstance -ClassName Win32_OperatingSystem).BuildNumber Switch -Wildcard ( $OS ) { '21*' { $OSVer = "Windows 10" Write-Warning "This script is intended for use on Windows 11 devices. $($OSVer) was detected..." Write-LogEntry -Value "This script is intended for use on Windows 11 devices. $($OSVer) was detected..." Exit 1 } } # Black List of Appx Provisioned Packages to Remove for All Users $BlackListedApps = $null $BlackListedApps = New-Object -TypeName System.Collections.ArrayList $BlackListedApps.AddRange(@( "Microsoft.OutlookForWindows", # Still present in 24H2 "MicrosoftCorporationII.QuickAssist", # Still present in 24H2 "Clipchamp.Clipchamp", # Still present in 24H2 "Microsoft.BingWeather", # Still present in 24H2 "Microsoft.BingNews", # Still present in 24H2 "Microsoft.GamingApp", # Still present in 24H2 "Microsoft.GetHelp", # Still present in 24H2 "Microsoft.Getstarted", # Still present in 24H2 #"Microsoft.Messaging", # May not be in 24H2 by default "Microsoft.MicrosoftOfficeHub", # Still present in 24H2 "Microsoft.MicrosoftSolitaireCollection", # Still present in 24H2 "Microsoft.MicrosoftStickyNotes", # Still present in 24H2 #"Microsoft.MSPaint", # Now "Microsoft.Paint" in 24H2 "Microsoft.Paint", # New name for Paint in 24H2 "Microsoft.People", # Still present in 24H2 "Microsoft.PowerAutomateDesktop", # Still present in 24H2 "Microsoft.StorePurchaseApp", # Still present in 24H2 "Microsoft.Todos", # Still present in 24H2 "microsoft.windowscommunicationsapps", # Still present in 24H2 "Microsoft.WindowsFeedbackHub", # Still present in 24H2 "Microsoft.WindowsMaps", # Still present in 24H2 "Microsoft.WindowsSoundRecorder", # Still present in 24H2 "Microsoft.Xbox.TCUI", # Still present in 24H2 "Microsoft.XboxGameOverlay", # Still present in 24H2 "Microsoft.XboxGamingOverlay", # Still present in 24H2 "Microsoft.XboxIdentityProvider", # Still present in 24H2 "Microsoft.XboxSpeechToTextOverlay", # Still present in 24H2 "Microsoft.YourPhone", # Still present in 24H2 "Microsoft.ZuneMusic", # Still present in 24H2 #"Microsoft.ZuneVideo", # May be "Microsoft.Movies" in 24H2 "Microsoft.BingSearch", # Still present in 24H2 "MicrosoftWindows.CrossDevice", # Still present in 24H2 "Microsoft.Windows.DevHome", # Still present in 24H2 "MSTeams" # Still present in 24H2 )) #Define Icons $CheckIcon = @{ Object = [Char]8730 ForegroundColor = 'Green' NoNewLine = $true } #Define App Count [int]$AppCount = 0 If ($($BlackListedApps.Count) -ne 0) { Write-Output `n"The following $($BlackListedApps.Count) apps were targeted for removal from the device:-" Write-LogEntry -Value "The following $($BlackListedApps.Count) apps were targeted for removal from the device:-" Write-LogEntry -Value "Apps marked for removal:$($BlackListedApps)" Write-Output "" $BlackListedApps #Initialize list for apps not targeted $AppNotTargetedList = New-Object -TypeName System.Collections.ArrayList # Get Appx Provisioned Packages Write-Output `n"Gathering installed Appx Provisioned Packages..." Write-LogEntry -Value "Gathering installed Appx Provisioned Packages..." Write-Output "" $AppArray = Get-AppxProvisionedPackage -Online | Select-Object -ExpandProperty DisplayName # Loop through each Provisioned Package foreach ($BlackListedApp in $BlackListedApps) { # Function call to Remove Appx Provisioned Packages defined in the Black List if (($BlackListedApp -in $AppArray)) { $AppCount ++ Try { Remove-AppxProvisionedPackageCustom -BlackListedApp $BlackListedApp } Catch { Write-Warning `n"There was an error while attempting to remove $($BlakListedApp)" Write-LogEntry -Value "There was an error when attempting to remove $($BlakListedApp)" } } else { $AppNotTargetedList.AddRange(@($BlackListedApp)) } } #Update Output Information If (!([string]::IsNullOrEmpty($AppNotTargetedList))) { Write-Output `n"The following apps were not removed. Either they were already removed or the Package Name is invalid:-" Write-LogEntry -Value "The following apps were not removed. Either they were already removed or the Package Name is invalid:-" Write-LogEntry -Value "$($AppNotTargetedList)" Write-Output "" $AppNotTargetedList } If ($AppCount -eq 0) { Write-Output `n"No apps were removed. Most likely reason is they had been removed previously." Write-LogEntry -Value "No apps were removed. Most likely reason is they had been removed previously." } } else { Write-Output "No Black List Apps defined in array" Write-LogEntry -Value "No Black List Apps defined in array" } Stop-Transcript | Out-Null #endregion #region Update Drivers #================================================= Write-SectionHeader "Update Drivers" #================================================= $Title = 'Update Drivers' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) if (!(Get-Module PSWindowsUpdate -ListAvailable -ErrorAction Ignore)) { try { Write-DarkGrayHost "Installing PSWindowsUpdate module" Install-Module PSWindowsUpdate -Force Import-Module PSWindowsUpdate -Force } catch { Write-Warning "Unable to install PSWindowsUpdate Driver Updates : $($_.Exception.Message)" } } if (Get-Module PSWindowsUpdate -ListAvailable -ErrorAction Ignore) { Write-DarkGrayHost "Executing 'Install-WindowsUpdate -UpdateType Driver -AcceptAll -IgnoreReboot'" Install-WindowsUpdate -UpdateType Driver -AcceptAll -IgnoreReboot } #endregion #region Update Windows #================================================= Write-DarkGrayHost "Update Windows" #================================================= $Title = 'Update Windows' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) if (!(Get-Module PSWindowsUpdate -ListAvailable)) { try { Write-DarkGrayHost "Installing PSWindowsUpdate module" Install-Module PSWindowsUpdate -Force Import-Module PSWindowsUpdate -Force } catch { Write-Warning 'Unable to install PSWindowsUpdate Windows Updates' } } if (Get-Module PSWindowsUpdate -ListAvailable -ErrorAction Ignore) { Write-DarkGrayHost "Executing 'Add-WUServiceManager -MicrosoftUpdate -Confirm:$false'" Add-WUServiceManager -MicrosoftUpdate -Confirm:$false #Write-Host -ForegroundColor DarkCyan 'Install-WindowsUpdate -UpdateType Software -AcceptAll -IgnoreReboot' #Install-WindowsUpdate -UpdateType Software -AcceptAll -IgnoreReboot -NotTitle 'Malicious' Write-DarkGrayHost "Executing 'Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -IgnoreReboot'" Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -IgnoreReboot -NotTitle 'Preview' -NotKBArticleID 'KB890830', 'KB5005463', 'KB4481252' } #endregion #region Remove DevHome & Outlook NEW #================================================= Write-DarkGrayHost "Remove DevHome & Outlook NEW" #================================================= $Title = 'Remove DevHome & Outlook NEW' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) $DevHome = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate" $OutlookNew = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate" if (Test-Path -Path $DevHome) { Write-DarkGrayHost "Found --> Removing DevHome" Remove-Item -Path $DevHome -Force } if (Test-Path -Path $OutlookNew) { Write-DarkGrayHost "Found --> Removing Outlook NEW" Remove-Item -Path $OutlookNew -Force } #endregion #region Disable PowerShell 2.0 #================================================= Write-DarkGrayHost "Disable PowerShell 2.0" #================================================= $Title = 'Disable PowerShell 2.0' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) #If PowerShell version 2 is installed, it’s possible to bypass the constrained language mode, which normally is being enforced by application control solutions like AppLocker and similar. try { $PoShv2Enabled = Get-WindowsOptionalFeature -FeatureName "MicrosoftWindowsPowerShellV2Root" -Online | Select-Object -ExpandProperty State } catch { Write-Error "Failed to get the state of the PowerShell v2.0 feature: : $($_.Exception.Message)" } # If the feature is enabled, try to disable it if ($PoShv2Enabled -eq "Enabled") { try { Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root -ErrorAction Continue -NoRestart } catch { Write-Error "Failed to disable the PowerShell v2.0 feature: $($_.Exception.Message)" } } #endregion #region Stop Start menu from opening on first logon #================================================= Write-SectionHeader "Stop Start menu from opening on first logon" #================================================= $Title = 'Stop Start menu from opening on first logon' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) try { reg.exe load HKLM\TempUser "C:\Users\Default\NTUSER.DAT" | Out-Host reg.exe add "HKLM\TempUser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v StartShownOnUpgrade /t REG_DWORD /d 1 /f | Out-Host reg.exe unload HKLM\TempUser | Out-Host } catch { Write-Warning "Unable to stop Start menu from opening on first logon: : $($_.Exception.Message)" } #endregion #region Removes Microsoft Quick Assist #================================================= Write-SectionHeader "Removes Microsoft Quick Assist" #================================================= $Title = 'Removes Microsoft Quick Assist' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) # Define the app package name $appPackageName = "MicrosoftCorporationII.QuickAssist" # Function to remove the app for the current user function Remove-AppxPackageByName { param ( [string]$PackageName ) $app = Get-AppxPackage -Name $PackageName -ErrorAction SilentlyContinue if ($app) { Remove-AppxPackage -Package $app.PackageFullName -ErrorAction SilentlyContinue Write-Output "Removed app package $PackageName for current user." } else { Write-Output "App package $PackageName not found for current user." } } # Function to remove the provisioned app function Remove-AppxProvisionedPackageByName { param ( [string]$PackageName ) $app = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq $PackageName } if ($app) { Remove-AppxProvisionedPackage -Online -PackageName $app.PackageName -ErrorAction SilentlyContinue Write-Output "Removed provisioned app package $PackageName." } else { Write-Output "Provisioned app package $PackageName not found." } } try { # Remove Quick Assist for the current user Remove-AppxPackageByName -PackageName $appPackageName # Remove the provisioned package so it does not get installed for new users Remove-AppxProvisionedPackageByName -PackageName $appPackageName Write-Output "Microsoft Quick Assist removal process completed." } catch { Write-Warning 'Unable to remove Microsoft Quick Assist' } #endregion #region OEM Branding #================================================= Write-SectionHeader "OEM Branding" #================================================= $Title = 'OEM Branding' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) try { #reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation" /v Manufacturer /t REG_SZ /d "XXX" /f /reg:64 | Out-Host reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportPhone /t REG_SZ /d "+41 xx xxx xx xx" /f /reg:64 | Out-Host #reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportHours /t REG_SZ /d "XXX" /f /reg:64 | Out-Host reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportURL /t REG_SZ /d "helpdesk@mme.ch" /f /reg:64 | Out-Host reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v RegisteredOwner /t REG_SZ /d "MME Legal | Tax | Compliance" /f /reg:64 | Out-Host reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v RegisteredOrganization /t REG_SZ /d "MME Legal | Tax | Compliance" /f /reg:64 | Out-Host } catch { Write-Warning "Unable to set the OEM Branding: $($_.Exception.Message)" } #endregion #region CMTrace Download #================================================= Write-SectionHeader "CMTrace Download" #================================================= $Title = 'CMTrace Download' $host.ui.RawUI.WindowTitle = "$Title" $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size(2000, 2000) try { $url = 'https://patchmypc.com/cmtrace' $destDir = 'C:\Program Files\CMTrace' $exePath = Join-Path $destDir 'CMTrace.exe' # Create destination New-Item -Path $destDir -ItemType Directory -Force | Out-Null # Download directly to final path Write-DarkGrayHost "Downloading CMTrace to $exePath..." Invoke-WebRequest -Uri $url -OutFile $exePath -ErrorAction Stop | Out-Null # Basic validation (PE header "MZ") $header = [byte[]](Get-Content -Path $exePath -Encoding Byte -TotalCount 2) if ($header.Length -ne 2 -or $header[0] -ne 0x4D -or $header[1] -ne 0x5A) { Remove-Item $exePath -Force -ErrorAction SilentlyContinue throw "Downloaded file doesn't look like a valid executable." } } catch { Write-Warning "Unable to download CMTrace: $($_.Exception.Message)" } #Read-Host -Prompt "Stopping for further troubleshootings. Press Enter to continue..." Stop-Transcript | Out-Null