Problem overview
Upgrading large fleets of Windows 10 devices to Windows 11 can be time-consuming and error-prone when done manually, especially for IT Professionals managing numerous endpoints. This script automates the entire process using Microsoft’s official Installation Assistant, helping ensure your transitions remain consistent, efficient, and less prone to human oversight.
<#
This resource is provided as a convenience for Level users. We cannot
guarantee it will work in all environments. Please test before deploying
to your production environment. We welcome contributions to our community
library
Level Library
https://level.io/library/script-upgrade-to-windows-11
#>
# Step 1: Setup
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Script started..."
# Define necessary paths and variables
$installerPath = "C:\temp\Windows11UpdateAssistant.exe"
$tempDir = "C:\temp"
# Step 2: Check if temporary directory exists, create if not
if (-Not (Test-Path $tempDir)) {
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Created directory '$tempDir'."
} else {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Directory '$tempDir' already exists."
}
# Step 3: Download the Windows 11 Installation Assistant
$url = "https://go.microsoft.com/fwlink/?linkid=2171764"
try {
Invoke-WebRequest -Uri $url -OutFile $installerPath -ErrorAction Stop
$FileSize = [math]::round((Get-Item -Path $installerPath).Length/1MB,2)
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Windows 11 Installation Assistant downloaded to '$installerPath' - $FileSize MB."
} catch {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [ERROR] - Failed to download Windows 11 Installation Assistant. $_"
exit 1
}
# Step 4: Start the Windows 11 upgrade process
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Starting Windows 11 upgrade process."
$process = Start-Process -FilePath $installerPath -ArgumentList "/quietinstall /skipeula /auto upgrade /NoRestartUI /noreboot /copylogs $tempDir" -PassThru -Wait
# Step 5: Check if the process was successfully initiated and check the exit code
if ($process.ExitCode -ne 0) {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [ERROR] - The Windows 11 upgrade process failed with exit code $($process.ExitCode)."
# Step 6: Extract errors from setup logs if available
if (Test-Path $tempDir) {
$setupActLog = Join-Path -Path $tempDir -ChildPath "setupact.log"
$setupErrLog = Join-Path -Path $tempDir -ChildPath "setuperr.log"
# Extract errors and warnings from setupact.log
if (Test-Path $setupActLog) {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [DEBUG] - Extracting warnings and errors from '$setupActLog'."
Select-String -Path $setupActLog -Pattern "Error", "Warning" | ForEach-Object {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [DEBUG] - $($_.Line)"
}
}
# Extract errors and warnings from setuperr.log
if (Test-Path $setupErrLog) {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [DEBUG] - Extracting warnings and errors from '$setupErrLog'."
Select-String -Path $setupErrLog -Pattern "Error", "Warning" | ForEach-Object {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [DEBUG] - $($_.Line)"
}
}
}
exit 1
} else {
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - The Windows 11 upgrade process completed successfully with exit code 0."
}
# Step 7: Clean up the installer
if (Test-Path $installerPath) {
Remove-Item -Path $installerPath -Force
Write-Output "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Cleaned up installer from '$installerPath'."
}
# Step 8: Exit with a success code
exit 0 This script first checks for or creates a temporary folder, then downloads the Windows 11 Installation Assistant directly from Microsoft, storing it locally. It proceeds to launch a silent upgrade with minimal user interaction, tracks any error codes, and logs issues to assist troubleshooting. Once the process is complete, the script cleans up the installer to reclaim space and neatly finalizes the upgrade.
With built-in logging, it offers detailed insights into both successful upgrades and potential failures, allowing you to quickly pinpoint and address problems. The entire flow runs under system permissions, letting you execute remote or automated upgrades without manual steps.
Use cases
- Performing bulk in-place upgrades from Windows 10 to Windows 11 across multiple clients
- Simplifying OS deployment for newly procured devices or refresh cycles
- Automating standardization to Windows 11 for compliance or security requirements
- Reducing manual oversight during major version migrations
Recommendations
- Always test in a non-production environment before large-scale deployments
- Configure a script-based monitor in Level to run this script on-demand for one-off upgrades
- Consider building a tag based automation in Level that executes this script on targeted endpoints. See our Windows 11 Upgrade Automation
- Verify hardware readiness (such as disk space, TPM version, and CPU requirements) to avoid unexpected failures
- Ensure endpoints have sufficient internet connectivity for the Installation Assistant download
- Keep logs for troubleshooting and consult the official Microsoft documentation for known upgrade issues