This guide finds the Windows 10 devices that can move to Windows 11 and then starts the upgrade on them automatically. It relies on Fleet policies and PowerShell scripts.
Feature/Functionality
Overview
The process has three stages:
- Read the TPM 2.0 and Secure Boot status of each device and save it in the Windows registry.
- Check the hardware and software requirements to decide which devices qualify.
- Download Windows 11 and install it silently on the devices that qualify.
How to use
Step 1. Record TPM and Secure Boot in the registry
- Create a policy with the query below. It checks whether the two registry keys that hold the TPM and Secure Boot status already exist.
SELECT 1 WHERE EXISTS (
SELECT 1 FROM registry
WHERE path = 'HKEY_LOCAL_MACHINE\Software\FleetDM\TPMVersion'
)
AND EXISTS (
SELECT 1 FROM registry
WHERE path = 'HKEY_LOCAL_MACHINE\Software\FleetDM\SecureBoot'
);- Attach the PowerShell script below to that policy. It reads the TPM version and the Secure Boot status and writes both values to the registry.
$TPM = Get-WmiObject -Namespace "Root\CIMv2\Security\MicrosoftTpm" -Class Win32_Tpm
$SecureBoot = Confirm-SecureBootUEFI
$TPMVersion = $TPM.SpecVersion
$SecureBootEnabled = if ($SecureBoot) { 1 } else { 0 }
# Write values to the registry (example)
New-Item -Path "HKLM:\Software\FleetDM" -Force | Out-Null
Set-ItemProperty -Path "HKLM:\Software\FleetDM" -Name "TPMVersion" -Value $TPMVersion
Set-ItemProperty -Path "HKLM:\Software\FleetDM" -Name "SecureBoot" -Value $SecureBootEnabledWhen the script has run, HKLM\Software\FleetDM\TPMVersion and HKLM\Software\FleetDM\SecureBoot exist and hold the current values.
Step 2. Check which Windows 10 devices qualify
- Create a second policy with the query below. It checks RAM, CPU cores, architecture, TPM 2.0 and Secure Boot.
SELECT 1 FROM os_version as os JOIN system_info as si WHERE
os.name NOT LIKE 'Microsoft Windows 10%'
OR si.physical_memory < 4 * 1024 * 1024 * 1024
OR si.cpu_physical_cores < 2
OR si.cpu_type NOT LIKE '%x86_64%'
OR NOT EXISTS (
SELECT * FROM registry
WHERE path = 'HKEY_LOCAL_MACHINE\Software\FleetDM\TPMVersion'
AND data LIKE '2%'
)
OR NOT EXISTS (
SELECT * FROM registry
WHERE path = 'HKEY_LOCAL_MACHINE\Software\FleetDM\SecureBoot'
AND data = '1'
);- Read the result the right way round: the query returns 1 when the device is not an eligible Windows 10 machine. Treat it as a non-compliance policy. The devices where it does not return 1 are the ones you can upgrade.
Step 3. Start the upgrade on eligible devices
- Attach the script below to the devices that passed step 2.
- The script downloads the Windows 11 ISO, mounts it, copies the installation files to the local disk and schedules a silent setup that runs as SYSTEM.
# Imports
Import-Module BitsTransfer
# Variables
$uri = "https://production-bucket-public-files.s3.eu-west-3.amazonaws.com/Win11_24H2_French_x64.iso" # French locale — replace with the appropriate locale ISO for your region
$destination = "C:\Win11.iso"
$log = "C:\logs\download_win11_iso.log"
# Create the logs folder if it doesn't exist
if (-not (Test-Path -Path "C:\logs")) {
New-Item -Path "C:\logs" -ItemType Directory | Out-Null
}
# Start the download
try {
"`n[$(Get-Date)] Starting download..." | Out-File -Append $log
if (-not (Test-Path $destination)){
Start-BitsTransfer -Source $uri -Destination $destination
}
"`n[$(Get-Date)] Download completed successfully." | Out-File -Append $log
} catch {
"`n[$(Get-Date)] Error during download: $_" | Out-File -Append $log
}
# Additional variables
$isoPath = "C:\Win11.iso"
$setupFolder = "C:\Temp\Win11Files"
$taskName = "Win11SilentUpgrade"
# Step 1 - Mount the ISO
Mount-DiskImage -ImagePath $isoPath -PassThru | Out-Null
Start-Sleep -Seconds 2
$vol = Get-Volume -DiskImage (Get-DiskImage -ImagePath $isoPath)
$driveLetter = $vol.DriveLetter
# Step 2 - Copy ISO content locally
New-Item -ItemType Directory -Force -Path $setupFolder | Out-Null
Copy-Item "$driveLetter`:\*" -Destination $setupFolder -Recurse
# Unmount the ISO
Dismount-DiskImage -ImagePath $isoPath
# Step 3 - Create and schedule the installation task
$action = New-ScheduledTaskAction -Execute "C:\Temp\Win11Files\setup.exe" -Argument "/auto upgrade /migratedrivers none /resizerecoverypartition enable /dynamicupdate disable /eula accept /quiet /noreboot /uninstall disable /compat ignorewarning /copylogs C:\logs\WinSetup.log"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1))
Register-ScheduledTask -TaskName $taskName -InputObject $task -Force
# Step 4 - Start the task immediately
Start-ScheduledTask -TaskName $taskNameTips and Best Practices
- Change the ISO before you run anything. The script points to a French ISO. Replace the URL with the ISO for your language and region.
- Run step 1 first and give it time. Step 2 depends on the registry values written in step 1. A device without them always shows as not eligible.
- Start with a small group. The setup runs silently and without a restart prompt. Try it on a few devices before the whole fleet.
-
Keep the logs. The download log goes to
C:\logs\download_win11_iso.logand the setup log toC:\logs\WinSetup.log. Check them first when something fails. - Plan for the download. Each device pulls a full Windows 11 ISO, so avoid slow or pay-per-use connections.
Troubleshooting and FAQ
Troubleshooting
- A device you expected to qualify shows as not eligible. Check that the step 1 script has run on it and that both registry keys exist. Then check the requirements in the step 2 query: Windows 10, at least 4 GB of RAM, at least 2 physical CPU cores, an x86_64 processor, TPM version 2 and Secure Boot turned on.
-
The upgrade did not start. Open
C:\logs\download_win11_iso.logto see whether the ISO downloaded. If it did, look for theWin11SilentUpgradescheduled task on the device. -
The setup failed partway. Read
C:\logs\WinSetup.log, where the script tells Windows setup to copy its logs.
FAQ
-
Does the step 2 query return the eligible devices?
No, the opposite. It returns 1 for devices that do not qualify. Eligible devices are the ones where it does not return 1.
-
Why save TPM and Secure Boot in the registry?
So the eligibility policy can read them with a plain registry query.
-
Which account runs the upgrade?
SYSTEM, through a scheduled task that the script creates and starts straight away.
-
Does the script restart the device?
The setup command includes/noreboot, so the script does not force a restart itself.