At work, we’ve been having some issues crop up, mainly around Office 365 suite, but it seemed to be more present on systems with Windows 10 21H2 than systems that were upgraded to 22H2 already. So I needed to find a way I could easily upgrade dozens of machines without having to login to each one.
We use Pulseway RMM to manage machines, but on the couple I tried to check, it wasn’t showing 22H2 as an available update. So I hit up Google and started searching. Took a little bit to find, but I came across this Reddit article: https://www.reddit.com/r/PowerShell/comments/zz4t7b/upgrade_windows_10_to_22h2/
The person had written a Powershell script that would download the latest ISO installer, extract the ISO to a folder and then trigger setup to run silently. I thought this was perfect, it should do exactly what I need. Now I had just reloaded a few machines in the last week or two, so I had recent ISOs already downloaded. Instead of downloading the ISO from the internet onto dozens of systems, I figured I’d stored the already downloaded ISOs on the DC and let it copy them from there.
Now I haven’t exactly figured out how to use all the Scope settings in Pulseway yet, so I also needed a way to check the Windows version number before running the rest of the script. I found this command that allowed me to check the current version via Powershell:
(Get-CimInstance Win32_OperatingSystem).version
Since most of our machines are 21H2, this came back as 10.0.19044. Here is the list of numbers I found:
Win10 21H2 10.0.19044
Win10 22H2 10.0.19045
Win11 21H2 10.0.22000
Win11 22H2 10.0.22621
So for my windows 10 machines, if the version matched 10.0.19044, the script would keep going, if not, it would exit and quit.
Here is the finished Windows 10 script:
$WinVer = (Get-CimInstance Win32_OperatingSystem).version
If (!($WinVer -match '10.0.19044')) { exit }
If (!(Test-Path C:\WindowsSetup)) {
New-Item -ItemType Directory -Path "C:\WindowsSetup"
}
copy \\DCServerName\NETLOGON\Installs\Win11_22H2.iso c:\windowssetup
$DownloadPath = "C:\WindowsSetup\Win11_22H2.iso"
$mountResult = Mount-DiskImage -ImagePath $DownloadPath
$driveLetter = ($mountResult | Get-Volume).DriveLetter
$ExtractPath = $driveLetter + ":\*"
Copy-Item -Path "$ExtractPath" -Destination "C:\WindowsSetup\" -Recurse -Force -Verbose
Dismount-DiskImage -ImagePath $DownloadPath
Remove-Item "C:\WindowsSetup\Win11_22H2.iso" -Force
$ArgumentList = "/auto upgrade /eula accept /quiet"
Start-Process -NoNewWindow -Wait -FilePath "C:\WindowsSetup\setup.exe" -ArgumentList $ArgumentList
Here is the finished Windows 11 script:
$WinVer = (Get-CimInstance Win32_OperatingSystem).version
If (!($WinVer -match '10.0.22000')) { exit }
If (!(Test-Path C:\WindowsSetup)) {
New-Item -ItemType Directory -Path "C:\WindowsSetup"
}
copy \\DCServerName\NETLOGON\Installs\Win11_22H2.iso c:\windowssetup
$DownloadPath = "C:\WindowsSetup\Win11_22H2.iso"
$mountResult = Mount-DiskImage -ImagePath $DownloadPath
$driveLetter = ($mountResult | Get-Volume).DriveLetter
$ExtractPath = $driveLetter + ":\*"
Copy-Item -Path "$ExtractPath" -Destination "C:\WindowsSetup\" -Recurse -Force -Verbose
Dismount-DiskImage -ImagePath $DownloadPath
Remove-Item "C:\WindowsSetup\Win11_22H2.iso" -Force
$ArgumentList = "/auto upgrade /eula accept /quiet"
Start-Process -NoNewWindow -Wait -FilePath "C:\WindowsSetup\setup.exe" -ArgumentList $ArgumentList
You’ll need to modify the copy command to point to your server name. Also, as the original Reddit post points out, if you don’t want it to auto reboot, you can add the /noreboot switch to the $ArgumentList line.