├── .gitignore ├── DirectWindowsUpgrade.ps1 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dev/ 2 | -------------------------------------------------------------------------------- /DirectWindowsUpgrade.ps1: -------------------------------------------------------------------------------- 1 | # Direct Windows 11 Upgrade - No GUI 2 | # 3 | # This script performs a silent in-place upgrade to Windows 11, supporting: 4 | # - Upgrading from Windows 10 to Windows 11 5 | # - Upgrading from older Windows 11 versions to newer versions (e.g., 21H2 to 22H2) 6 | # - Completely silent operation with no user interaction required 7 | # - Bypassing TPM, CPU, and other hardware compatibility checks 8 | # 9 | # PROCESS DETAILS: 10 | # - The script will install 7-Zip if not already present (required to extract ISO contents) 11 | # - Total upgrade process takes approximately 1.5 hours to complete 12 | # - By default, the system will automatically reboot when necessary (configurable) 13 | # - No user intervention is required at any point in the process 14 | # 15 | # USAGE NOTES: 16 | # 1. Edit the configuration section below to specify your Windows 11 ISO source 17 | # 2. Make sure to use an ISO containing the Windows 11 version you want to upgrade to 18 | # 3. Recommended ISO source: https://massgrave.dev/genuine-installation-media.html 19 | # 4. Run this script with administrative privileges 20 | 21 | ####################################################################### 22 | # CONFIGURATION - MODIFY THESE SETTINGS AS NEEDED 23 | ####################################################################### 24 | 25 | # Specify the Windows 11 ISO source - MODIFY THIS FOR YOUR ENVIRONMENT 26 | # Options: 27 | # 1. Direct download URL (default) 28 | # 2. Local file path (e.g., "C:\Path\To\Windows11.iso") 29 | # 3. Network share (e.g., "\\server\share\Windows11.iso") 30 | # 31 | # IMPORTANT: The ISO must contain the Windows 11 version you want to upgrade to. 32 | # Business editions are recommended as they have fewer issues with silent upgrades. 33 | # You can download official ISOs from: https://massgrave.dev/genuine-installation-media.html 34 | $WIN11_ISO_SOURCE = "https://replace/this/url/with/your/iso/windows.iso" 35 | 36 | # WORKING DIRECTORIES - you can modify these if needed 37 | $WORKING_DIR = "C:\Win11Upgrade" # Main working directory 38 | $TEMP_DIR = "C:\Windows\Temp" # Temporary directory 39 | $LOG_FILE = "C:\Win11_Upgrade_Progress.log" # Main log file 40 | $MONITOR_LOG = "C:\Win11_Monitor.log" # Process monitor log file 41 | 42 | # BEHAVIOR SETTINGS 43 | $BYPASS_CONFIRMATION = $false # Set to $true to skip all confirmation prompts 44 | $ALLOW_AUTOMATIC_REBOOT = $true # Set to $false to prevent automatic reboots 45 | 46 | ####################################################################### 47 | # SCRIPT BEGINS HERE - DO NOT MODIFY BELOW THIS LINE UNLESS NECESSARY 48 | ####################################################################### 49 | 50 | # Ensure running as admin 51 | if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { 52 | Write-Host "ERROR: This script requires administrator privileges." -ForegroundColor Red 53 | Write-Host "Please restart the script with administrator rights." -ForegroundColor Yellow 54 | exit 1 55 | } 56 | 57 | # Use the ISO source defined at the top of the script 58 | $isoUrl = $WIN11_ISO_SOURCE 59 | $isoPath = "$TEMP_DIR\windows11.iso" 60 | 61 | # Validate the URL or file path before doing anything else 62 | if ($isoUrl -eq "https://replace/this/url/with/your/iso/windows.iso") { 63 | Write-Host "ERROR: You need to replace the placeholder URL in the configuration section." -ForegroundColor Red 64 | Write-Host "Please edit the script and update the `$WIN11_ISO_SOURCE variable with a valid ISO URL or file path." -ForegroundColor Yellow 65 | exit 1 66 | } 67 | 68 | # Show confirmation prompt 69 | Write-Host "WARNING: You are about to start an automated Windows 11 upgrade process." -ForegroundColor Yellow 70 | Write-Host "" 71 | Write-Host "The following will occur if you proceed:" 72 | Write-Host "- 7-Zip will be installed (if not already present)" 73 | Write-Host "- System settings will be modified" 74 | Write-Host "- Your PC will reboot when the installation is ready" 75 | Write-Host "- The entire process takes approximately 1.5 hours" 76 | Write-Host "" 77 | Write-Host "IMPORTANT NOTES:" -ForegroundColor Cyan 78 | Write-Host "- Please be patient during the upgrade process" 79 | Write-Host "- As long as SetupHost.exe is running in Task Manager, the upgrade is working" 80 | Write-Host "- The process may appear to stall at times, but this is normal" 81 | Write-Host "- Do not interrupt the process once it has started" 82 | Write-Host "" 83 | 84 | if (-not $BYPASS_CONFIRMATION) { 85 | $confirmation = Read-Host "Do you want to continue with the Windows 11 upgrade? (y/n)" 86 | if ($confirmation -ne 'y' -and $confirmation -ne 'Y') { 87 | Write-Host "Windows 11 upgrade cancelled by user." 88 | exit 0 89 | } 90 | } else { 91 | Write-Host "Confirmation bypassed. Proceeding with Windows 11 upgrade automatically..." -ForegroundColor Yellow 92 | } 93 | 94 | # Set aggressive compatibility bypass registry keys 95 | Write-Host "Setting comprehensive compatibility bypass registry keys..." 96 | 97 | # TPM and basic hardware checks 98 | reg add "HKLM\SYSTEM\Setup\MoSetup" /f /v AllowUpgradesWithUnsupportedTPMorCPU /d 1 /t reg_dword 99 | reg add "HKLM\SYSTEM\Setup\LabConfig" /f /v BypassTPMCheck /d 1 /t reg_dword 100 | reg add "HKLM\SYSTEM\Setup\LabConfig" /f /v BypassSecureBootCheck /d 1 /t reg_dword 101 | reg add "HKLM\SYSTEM\Setup\LabConfig" /f /v BypassRAMCheck /d 1 /t reg_dword 102 | reg add "HKLM\SYSTEM\Setup\LabConfig" /f /v BypassStorageCheck /d 1 /t reg_dword 103 | reg add "HKLM\SYSTEM\Setup\LabConfig" /f /v BypassCPUCheck /d 1 /t reg_dword 104 | 105 | # Safeguard overrides 106 | reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /f /v DisableWUfBSafeguards /d 1 /t reg_dword 107 | reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\UpdatePolicy\Settings" /f /v DisableWUfBSafeguards /d 1 /t reg_dword 108 | reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /f /v DisableSafeguards /d 1 /t reg_dword 109 | 110 | # Setup compatibility settings 111 | reg add "HKLM\SYSTEM\Setup\UpgradeCompat" /f /v IgnoreAllWarnings /d 1 /t reg_dword 112 | reg add "HKLM\SYSTEM\Setup\UpgradeCompat" /f /v IgnoreHWRequirements /d 1 /t reg_dword 113 | reg add "HKLM\SYSTEM\Setup\UpgradeCompat" /f /v IgnoreApplicationsOnUpgrade /d 1 /t reg_dword 114 | reg add "HKLM\SYSTEM\Setup\UpgradeCompat" /f /v IgnoreAppsOnUpgrade /d 1 /t reg_dword 115 | reg add "HKLM\SYSTEM\Setup\Status\UninstallWindow" /f /v UninstallActive /d 0 /t reg_dword 116 | 117 | # Disable compatibility checks 118 | reg add "HKLM\SYSTEM\Setup" /f /v BypassCompatibilityCheck /d 1 /t reg_dword 119 | 120 | # Disable error reporting during upgrade 121 | reg add "HKLM\SOFTWARE\Microsoft\PCHealth\ErrorReporting" /f /v DoReport /d 0 /t reg_dword 122 | reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /f /v Disabled /d 1 /t reg_dword 123 | 124 | # Skip setup compliance checks 125 | reg add "HKLM\SYSTEM\Setup" /f /v BypassComplianceCheck /d 1 /t reg_dword 126 | 127 | # Allow setup to continue despite errors 128 | reg add "HKLM\SYSTEM\Setup" /f /v AllowNonZeroExitStatus /d 1 /t reg_dword 129 | 130 | # Disable CEIP during setup 131 | reg add "HKLM\SOFTWARE\Policies\Microsoft\SQMClient\Windows" /f /v CEIPEnable /d 0 /t reg_dword 132 | 133 | # Force target platform version 134 | reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /f /v TargetReleaseVersion /d 1 /t reg_dword 135 | reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /f /v TargetReleaseVersionInfo /d "25H1" /t reg_sz 136 | 137 | # Function to validate URL - ensures the URL is reachable before download 138 | function Test-UrlIsValid { 139 | param ( 140 | [string]$Url 141 | ) 142 | 143 | try { 144 | # Simple HEAD request to check if URL is reachable 145 | $request = [System.Net.WebRequest]::Create($Url) 146 | $request.Method = "HEAD" 147 | $request.Timeout = 15000 # 15 seconds timeout 148 | $request.UserAgent = "Mozilla/5.0 Windows PowerShell Script" 149 | 150 | # Get the response 151 | $response = $request.GetResponse() 152 | 153 | # Check if we can access the URL 154 | $success = $response.StatusCode -eq [System.Net.HttpStatusCode]::OK 155 | 156 | # Show file size if available 157 | $contentLength = $response.Headers["Content-Length"] 158 | if ($contentLength) { 159 | $sizeInMB = [math]::Round([long]$contentLength / 1MB, 2) 160 | if ($sizeInMB -gt 1000) { 161 | Write-Host "File size: $([math]::Round($sizeInMB / 1024, 2)) GB" -ForegroundColor Cyan 162 | } else { 163 | Write-Host "File size: $sizeInMB MB" -ForegroundColor Cyan 164 | } 165 | } 166 | 167 | # Close the response 168 | $response.Close() 169 | return $success 170 | } 171 | catch { 172 | # Simple error message without details that could cause red dumps 173 | Write-Host "ERROR: Could not access the URL. Please verify it's correct and accessible." -ForegroundColor Red 174 | return $false 175 | } 176 | } 177 | 178 | # If the ISO source is a local file or network share, copy it to the temp directory 179 | if (Test-Path $isoUrl) { 180 | Write-Host "Using local/network ISO file: $isoUrl" 181 | 182 | # Verify it's an ISO file 183 | $extension = [System.IO.Path]::GetExtension($isoUrl).ToLower() 184 | if ($extension -ne ".iso") { 185 | Write-Host "Warning: The file does not have an .iso extension. It may not be a valid Windows installation image." -ForegroundColor Yellow 186 | if (-not $BYPASS_CONFIRMATION) { 187 | $continue = Read-Host "Do you want to continue anyway? (y/n)" 188 | if ($continue -ne 'y' -and $continue -ne 'Y') { 189 | Write-Host "Operation cancelled by user." 190 | exit 0 191 | } 192 | } else { 193 | Write-Host "Confirmation bypassed. Continuing despite non-ISO extension..." -ForegroundColor Yellow 194 | } 195 | } 196 | 197 | # Verify file size (ISO should be at least 3GB) 198 | $fileInfo = Get-Item $isoUrl 199 | $fileSizeMB = [math]::Round($fileInfo.Length / 1MB, 2) 200 | if ($fileSizeMB -lt 3000) { 201 | Write-Host "Warning: The ISO file is only $fileSizeMB MB in size, which is unusually small for a Windows 11 ISO." -ForegroundColor Yellow 202 | Write-Host "A typical Windows 11 ISO is 4-6 GB in size." -ForegroundColor Yellow 203 | if (-not $BYPASS_CONFIRMATION) { 204 | $continue = Read-Host "Do you want to continue anyway? (y/n)" 205 | if ($continue -ne 'y' -and $continue -ne 'Y') { 206 | Write-Host "Operation cancelled by user." 207 | exit 0 208 | } 209 | } else { 210 | Write-Host "Confirmation bypassed. Continuing despite small ISO size..." -ForegroundColor Yellow 211 | } 212 | } 213 | 214 | # Copy the file with progress indication for large files 215 | Write-Host "Copying ISO file to working location..." 216 | try { 217 | Copy-Item -Path $isoUrl -Destination $isoPath -Force 218 | if (-not (Test-Path $isoPath)) { 219 | throw "Failed to copy ISO file to destination" 220 | } 221 | Write-Host "ISO file copied successfully." 222 | } 223 | catch { 224 | Write-Error "Failed to copy ISO file: $_" 225 | exit 1 226 | } 227 | 228 | $isLocalFile = $true 229 | } else { 230 | # Validate the URL before attempting to download 231 | Write-Host "Validating ISO download URL: $isoUrl" 232 | if (-not (Test-UrlIsValid -Url $isoUrl)) { 233 | Write-Error "The specified URL does not appear to be valid or accessible." 234 | Write-Host "Please check the URL and ensure it points to a valid Windows 11 ISO file." -ForegroundColor Yellow 235 | exit 1 236 | } 237 | 238 | Write-Host "URL validation successful. Proceeding with download..." -ForegroundColor Green 239 | $isLocalFile = $false 240 | } 241 | 242 | # Download ISO if needed 243 | if (-not $isLocalFile) { 244 | Write-Host "Downloading Windows 11 ISO..." -ForegroundColor Cyan 245 | Write-Host "This may take some time depending on your internet connection speed." -ForegroundColor Cyan 246 | 247 | try { 248 | $webClient = New-Object System.Net.WebClient 249 | $webClient.Headers.Add("User-Agent", "Mozilla/5.0 Windows PowerShell Script") 250 | 251 | # Disable progress bar to improve download performance 252 | $ProgressPreference = 'SilentlyContinue' 253 | 254 | Write-Host "Download started at $(Get-Date)" -ForegroundColor Cyan 255 | $webClient.DownloadFile($isoUrl, $isoPath) 256 | Write-Host "Download completed at $(Get-Date)" -ForegroundColor Green 257 | 258 | # Restore progress preference 259 | $ProgressPreference = 'Continue' 260 | 261 | # Verify the download 262 | if (Test-Path $isoPath) { 263 | $fileInfo = Get-Item $isoPath 264 | $fileSizeMB = [math]::Round($fileInfo.Length / 1MB, 2) 265 | 266 | # Check if file size is reasonable for a Windows ISO 267 | if ($fileSizeMB -lt 3000) { 268 | Write-Host "Warning: The downloaded ISO is only $fileSizeMB MB, which is unusually small for a Windows 11 ISO." -ForegroundColor Yellow 269 | Write-Host "This might indicate a partial download or incorrect ISO source." -ForegroundColor Yellow 270 | if (-not $BYPASS_CONFIRMATION) { 271 | $continue = Read-Host "Do you want to continue anyway? (y/n)" 272 | if ($continue -ne 'y' -and $continue -ne 'Y') { 273 | Write-Host "Operation cancelled by user." 274 | exit 0 275 | } 276 | } else { 277 | Write-Host "Confirmation bypassed. Continuing despite small downloaded ISO size..." -ForegroundColor Yellow 278 | } 279 | } else { 280 | Write-Host "ISO downloaded successfully ($fileSizeMB MB)." -ForegroundColor Green 281 | } 282 | } else { 283 | throw "ISO download failed: File not found after download" 284 | } 285 | } catch { 286 | Write-Error "Failed to download the ISO: $_" 287 | exit 1 288 | } finally { 289 | # Ensure WebClient is disposed 290 | if ($webClient) { 291 | $webClient.Dispose() 292 | } 293 | } 294 | } else { 295 | Write-Host "ISO file ready: $isoPath" -ForegroundColor Green 296 | } 297 | 298 | # Create a working directory for extracted ISO content 299 | $extractDir = $WORKING_DIR 300 | if (Test-Path $extractDir) { 301 | # Clean any existing directory to avoid conflicts 302 | Write-Host "Cleaning existing working directory..." 303 | Remove-Item -Path "$extractDir\*" -Recurse -Force -ErrorAction SilentlyContinue 304 | } else { 305 | # Create new directory 306 | New-Item -Path $extractDir -ItemType Directory -Force | Out-Null 307 | } 308 | 309 | # Check for 7-Zip installation 310 | $7zipPath = "C:\Program Files\7-Zip\7z.exe" 311 | if (-not (Test-Path $7zipPath)) { 312 | # Try common alternative path for x86 on x64 systems 313 | $7zipPath = "C:\Program Files (x86)\7-Zip\7z.exe" 314 | if (-not (Test-Path $7zipPath)) { 315 | Write-Host "7-Zip not found. Attempting to download and install it..." 316 | 317 | # Download and install 7-Zip using dynamic method to get latest version 318 | try { 319 | # Settings 320 | $downloadPage = "https://www.7-zip.org/download.html" 321 | $downloadPath = "C:\Windows\Temp\7z.msi" 322 | 323 | # Download page content 324 | $webClient = New-Object System.Net.WebClient 325 | $htmlContent = $webClient.DownloadString($downloadPage) 326 | 327 | # Extract latest x64 MSI link from the current version section 328 | $latestSection = $htmlContent -split '

Download 7-Zip' | Select-Object -Index 1 329 | 330 | # Handle both 32-bit and 64-bit architectures 331 | if ([Environment]::Is64BitOperatingSystem) { 332 | $archPattern = '-x64\.msi' 333 | } else { 334 | $archPattern = '\.msi"' 335 | } 336 | 337 | $msiRelativePath = ($latestSection | Select-String -Pattern "href=`"(a/7z\d+.*?$($archPattern))" -AllMatches).Matches[0].Groups[1].Value 338 | 339 | # Construct full download URL 340 | $downloadUrl = "https://www.7-zip.org/$msiRelativePath" 341 | 342 | Write-Host "Downloading 7-Zip from $downloadUrl" 343 | 344 | # Download and install 345 | $webClient.DownloadFile($downloadUrl, $downloadPath) 346 | Start-Process msiexec.exe -ArgumentList "/i `"$downloadPath`" /quiet /norestart" -Wait 347 | 348 | # Verify installation 349 | if (-not (Test-Path "C:\Program Files\7-Zip\7z.exe")) { 350 | throw "Failed to install 7-Zip" 351 | } 352 | $7zipPath = "C:\Program Files\7-Zip\7z.exe" 353 | } catch { 354 | Write-Error "Failed to install 7-Zip: $_" 355 | Write-Error "Please install 7-Zip manually and try again." 356 | exit 1 357 | } 358 | } 359 | } 360 | 361 | # Extract ISO using 7-Zip 362 | Write-Host "Extracting ISO using 7-Zip (this may take 5-10 minutes)..." -ForegroundColor Cyan 363 | Write-Host "Please be patient while the ISO contents are extracted..." -ForegroundColor Cyan 364 | try { 365 | # Use Start-Process with redirected error streams to capture output without displaying it 366 | $processInfo = New-Object System.Diagnostics.ProcessStartInfo 367 | $processInfo.FileName = $7zipPath 368 | $processInfo.Arguments = "x -y -o`"$extractDir`" `"$isoPath`"" 369 | $processInfo.RedirectStandardError = $true 370 | $processInfo.RedirectStandardOutput = $true 371 | $processInfo.UseShellExecute = $false 372 | $processInfo.CreateNoWindow = $true 373 | 374 | $process = New-Object System.Diagnostics.Process 375 | $process.StartInfo = $processInfo 376 | $process.Start() | Out-Null 377 | 378 | # Record start time 379 | $startTime = Get-Date 380 | 381 | # Wait for process to complete (no spinner) 382 | $process.WaitForExit() 383 | 384 | # Show completion message with total time 385 | $extractionTime = [TimeSpan]::FromSeconds((Get-Date).Subtract($startTime).TotalSeconds) 386 | Write-Host "Extraction complete [" $extractionTime.ToString("hh\:mm\:ss") "]" -ForegroundColor Green 387 | 388 | # Get the output without displaying it 389 | $standardOutput = $process.StandardOutput.ReadToEnd() 390 | $standardError = $process.StandardError.ReadToEnd() 391 | 392 | # Check the exit code 393 | if ($process.ExitCode -ne 0) { 394 | # Format a user-friendly error message without dumping everything 395 | Write-Host "ERROR: 7-Zip extraction failed with exit code $($process.ExitCode)" -ForegroundColor Red 396 | Write-Host "The ISO file may be corrupted or incompatible." -ForegroundColor Yellow 397 | 398 | # Show minimal error information 399 | if (-not [string]::IsNullOrEmpty($standardError)) { 400 | $errorLines = $standardError -split "`n" 401 | $relevantError = ($errorLines | Where-Object { $_ -match "ERROR:" } | Select-Object -First 1) 402 | if ($relevantError) { 403 | Write-Host "Error details: $relevantError" -ForegroundColor Yellow 404 | } 405 | } 406 | 407 | exit 1 408 | } 409 | 410 | # Verify extraction succeeded 411 | $setupPath = "$extractDir\setup.exe" 412 | if (-not (Test-Path $setupPath)) { 413 | Write-Host "ERROR: Extraction completed but setup.exe was not found." -ForegroundColor Red 414 | Write-Host "This suggests the ISO does not contain a valid Windows installation." -ForegroundColor Yellow 415 | Write-Host "Please verify you are using a proper Windows 11 installation ISO." -ForegroundColor Yellow 416 | exit 1 417 | } 418 | 419 | Write-Host "ISO extracted successfully to $extractDir" -ForegroundColor Green 420 | 421 | # Create zero-byte appraiserres.dll to bypass TPM check 422 | Write-Host "Creating TPM check bypass..." 423 | $appraiserdllPath = "$extractDir\sources\appraiserres.dll" 424 | if (Test-Path $appraiserdllPath) { 425 | # Make a backup just in case 426 | Copy-Item -Path $appraiserdllPath -Destination "$appraiserdllPath.bak" -Force 427 | # Replace with zero-byte file 428 | Set-Content -Path $appraiserdllPath -Value "" -Force 429 | } else { 430 | # Create new zero-byte file if it doesn't exist 431 | New-Item -Path $appraiserdllPath -ItemType File -Force | Out-Null 432 | } 433 | 434 | # Create EI.cfg to avoid product key prompts 435 | $eiCfgPath = "$extractDir\sources\EI.cfg" 436 | Set-Content -Path $eiCfgPath -Value "[Channel]`n_Default" -Force 437 | 438 | # Create SetupConfig.ini 439 | $setupConfigPath = "$extractDir\sources\SetupConfig.ini" 440 | $setupConfig = @" 441 | [BeginSetupMode] 442 | SkipPrediagler=1 443 | DeviceEnumeration=1 444 | DiscoverSystemPartition=1 445 | 446 | [SetupConfig] 447 | ScratchDir=$env:SystemDrive\`$WINDOWS.~BT 448 | ScratchSpace=12000 449 | PreinstallKitSpace=8000 450 | "@ 451 | Set-Content -Path $setupConfigPath -Value $setupConfig -Force 452 | 453 | # Run setup.exe with appropriate arguments and stronger compatibility bypass options 454 | Write-Host "Starting Windows 11 upgrade from extracted ISO with maximum compatibility overrides..." 455 | 456 | # Create custom answer file to force upgrade 457 | $answerFilePath = "$extractDir\unattend.xml" 458 | $answerFileContent = @" 459 | 460 | 461 | 462 | 463 | Never 464 | 465 | 466 | false 467 | 468 | 469 | true 470 | OnError 471 | 472 | 473 | 474 | 475 | 476 | /IMAGE/INDEX 477 | 1 478 | 479 | 480 | 481 | 0 482 | 1 483 | 484 | OnError 485 | true 486 | 487 | 488 | 489 | true 490 | 491 | 492 | 493 | 1 494 | reg add HKLM\SYSTEM\Setup\LabConfig /v BypassTPMCheck /d 1 /t reg_dword /f 495 | 496 | 497 | 2 498 | reg add HKLM\SYSTEM\Setup\LabConfig /v BypassSecureBootCheck /d 1 /t reg_dword /f 499 | 500 | 501 | 3 502 | reg add HKLM\SYSTEM\Setup\LabConfig /v BypassRAMCheck /d 1 /t reg_dword /f 503 | 504 | 505 | 4 506 | reg add HKLM\SYSTEM\Setup\LabConfig /v BypassCPUCheck /d 1 /t reg_dword /f 507 | 508 | 509 | 5 510 | reg add HKLM\SYSTEM\Setup\LabConfig /v BypassStorageCheck /d 1 /t reg_dword /f 511 | 512 | 513 | 6 514 | reg add HKLM\SYSTEM\Setup\MoSetup /v AllowUpgradesWithUnsupportedTPMorCPU /d 1 /t reg_dword /f 515 | 516 | 517 | 518 | 519 | 520 | "@ 521 | Set-Content -Path $answerFilePath -Value $answerFileContent -Force 522 | Write-Host "Created custom unattend.xml file for compatibility bypass" 523 | 524 | # Try the alternate 'Server' product trick - update setup files 525 | Write-Host "Applying 'Server' product trick to bypass hardware checks..." 526 | try { 527 | $setupConfigDatPath = "$extractDir\sources\setupconfig.dat" 528 | if (Test-Path $setupConfigDatPath) { 529 | $content = Get-Content -Path $setupConfigDatPath -Encoding Byte 530 | $clientPattern = [System.Text.Encoding]::Unicode.GetBytes("Client") 531 | $serverPattern = [System.Text.Encoding]::Unicode.GetBytes("Server") 532 | 533 | $found = $false 534 | for ($i = 0; $i -lt $content.Length - $clientPattern.Length; $i++) { 535 | $matched = $true 536 | for ($j = 0; $j -lt $clientPattern.Length; $j++) { 537 | if ($content[$i + $j] -ne $clientPattern[$j]) { 538 | $matched = $false 539 | break 540 | } 541 | } 542 | 543 | if ($matched) { 544 | $found = $true 545 | for ($j = 0; $j -lt $serverPattern.Length; $j++) { 546 | $content[$i + $j] = $serverPattern[$j] 547 | } 548 | } 549 | } 550 | 551 | if ($found) { 552 | [System.IO.File]::WriteAllBytes($setupConfigDatPath, $content) 553 | Write-Host "Successfully modified setupconfig.dat to use Server edition bypass" 554 | } 555 | } 556 | } catch { 557 | Write-Host "Warning: Could not modify setupconfig.dat: $_" 558 | } 559 | # Setup command line arguments 560 | $arguments = @( 561 | "/auto", "upgrade", 562 | "/quiet", 563 | "/compat", "ignorewarning", 564 | "/migratedrivers", "all", 565 | "/showoobe", "none", 566 | "/telemetry", "disable", 567 | "/dynamicupdate", "enable", 568 | "/eula", "accept", 569 | "/unattend:$answerFilePath", 570 | "/product", "server", # Add server product parameter to bypass hardware checks 571 | "/pkey", "VK7JG-NPHTM-C97JM-9MPGT-3V66T" # Generic Windows 11 Pro key 572 | ) 573 | 574 | # Add /noreboot switch if automatic reboots are disabled 575 | if (-not $ALLOW_AUTOMATIC_REBOOT) { 576 | $arguments += "/noreboot" 577 | Write-Host "Automatic reboots are disabled. The system will need to be manually rebooted to complete the upgrade." 578 | } else { 579 | Write-Host "Automatic reboots are enabled. The system will reboot automatically when needed." 580 | } 581 | 582 | # Create a log file to track progress 583 | $logFile = $LOG_FILE 584 | Set-Content -Path $logFile -Value "Windows 11 Upgrade started at $(Get-Date)`r`n" -Force 585 | 586 | # Function to log progress 587 | function Write-ProgressLog { 588 | param( 589 | [string]$Message 590 | ) 591 | $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 592 | $logMessage = "[$timestamp] $Message" 593 | Write-Host $logMessage 594 | Add-Content -Path $logFile -Value $logMessage 595 | } 596 | 597 | # Function to check if Windows Setup is running 598 | function Is-SetupRunning { 599 | $setupProcesses = @( 600 | "SetupHost", # This is the critical process for actual Windows upgrade execution 601 | "setupprep", 602 | "setup", 603 | "Windows10UpgraderApp" 604 | ) 605 | 606 | foreach ($proc in $setupProcesses) { 607 | $running = Get-Process -Name $proc -ErrorAction SilentlyContinue 608 | if ($running) { 609 | if ($proc -eq "SetupHost") { 610 | Write-ProgressLog "CRITICAL SUCCESS: SetupHost.exe is running! This confirms the upgrade is properly underway." 611 | return @{Success = $true; Critical = $true} 612 | } 613 | return @{Success = $true; Critical = $false} 614 | } 615 | } 616 | return @{Success = $false; Critical = $false} 617 | } 618 | 619 | # Function to wait for SetupHost.exe to appear (the definitive sign that upgrade is working) 620 | function Wait-ForSetupHost { 621 | param ( 622 | [int]$TimeoutSeconds = 300, # Wait up to 5 minutes by default 623 | [int]$CheckIntervalSeconds = 5 624 | ) 625 | 626 | Write-ProgressLog "Waiting for SetupHost.exe to start (the critical process for Windows upgrades)..." 627 | 628 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() 629 | $timeoutMs = $TimeoutSeconds * 1000 630 | 631 | while ($stopwatch.ElapsedMilliseconds -lt $timeoutMs) { 632 | $setupHost = Get-Process -Name "SetupHost" -ErrorAction SilentlyContinue 633 | if ($setupHost) { 634 | $stopwatch.Stop() 635 | Write-ProgressLog "SUCCESS: SetupHost.exe started after $([math]::Round($stopwatch.ElapsedMilliseconds / 1000)) seconds." 636 | Write-ProgressLog "SetupHost.exe PID: $($setupHost.Id), Started at: $(Get-Date)" 637 | return $true 638 | } 639 | 640 | # Check for setupprep - it should start first and launch SetupHost 641 | $setupPrep = Get-Process -Name "setupprep" -ErrorAction SilentlyContinue 642 | if ($setupPrep) { 643 | Write-ProgressLog "setupprep.exe is running (PID: $($setupPrep.Id)). Waiting for it to launch SetupHost.exe..." 644 | } 645 | 646 | # Sleep before checking again 647 | Start-Sleep -Seconds $CheckIntervalSeconds 648 | } 649 | 650 | $stopwatch.Stop() 651 | Write-ProgressLog "WARNING: SetupHost.exe did not start within $TimeoutSeconds seconds." 652 | return $false 653 | } 654 | 655 | Write-ProgressLog "Starting Windows 11 upgrade from extracted ISO..." 656 | Write-ProgressLog "To monitor progress, check the log file at: $logFile" 657 | Write-ProgressLog "You can also look for these processes: SetupHost.exe, setupprep.exe, setup.exe" 658 | 659 | # Start setup without waiting 660 | $arguments += "/PostOOBE", "$extractDir\PostInstall.cmd" 661 | 662 | # Create a post-install script to log completion 663 | $postInstallScript = @" 664 | @echo off 665 | echo Windows 11 Upgrade completed at %DATE% %TIME% > C:\Win11_Upgrade_Completed.log 666 | "@ 667 | Set-Content -Path "$extractDir\PostInstall.cmd" -Value $postInstallScript -Force 668 | 669 | # Start the setup process 670 | Write-ProgressLog "Launching setup.exe with arguments: $($arguments -join ' ')" 671 | $process = Start-Process -FilePath $setupPath -ArgumentList $arguments -PassThru -NoNewWindow 672 | 673 | # Wait briefly to see if initial processes start 674 | Start-Sleep -Seconds 5 675 | 676 | # Check if setup is running and log process ID 677 | $setupStatus = Is-SetupRunning 678 | if ($setupStatus.Success) { 679 | $setupProcesses = Get-Process | Where-Object { $_.Name -match "setup|SetupHost" } 680 | foreach ($proc in $setupProcesses) { 681 | Write-ProgressLog "Setup process running: $($proc.Name) (PID: $($proc.Id))" 682 | } 683 | 684 | if ($setupStatus.Critical) { 685 | Write-ProgressLog "VERIFIED: SetupHost.exe is running! The upgrade is confirmed to be properly underway." 686 | } else { 687 | # SetupHost is not yet running - wait for it as it's the critical indicator 688 | Write-ProgressLog "Initial setup processes started, but waiting for SetupHost.exe (the critical component)..." 689 | 690 | # Wait for SetupHost to appear - this is the definitive test 691 | $setupHostStarted = Wait-ForSetupHost -TimeoutSeconds 600 # Wait up to 10 minutes 692 | 693 | if ($setupHostStarted) { 694 | Write-ProgressLog "UPGRADE CONFIRMED: SetupHost.exe is running. The Windows 11 upgrade is now definitely underway." 695 | Write-ProgressLog "This is the critical process that indicates the actual upgrade is proceeding correctly." 696 | } else { 697 | Write-ProgressLog "WARNING: SetupHost.exe did not start within the expected timeframe." 698 | Write-ProgressLog "The upgrade may still proceed, but you should monitor it carefully." 699 | Write-ProgressLog "If the upgrade does not complete, you may need to run the script again." 700 | } 701 | } 702 | 703 | Write-ProgressLog "Setup initiated. The upgrade is now running in the background." 704 | Write-ProgressLog "To check if it's running, use Task Manager to look for SetupHost.exe." 705 | } else { 706 | Write-ProgressLog "Warning: Setup may not have started correctly." 707 | Write-ProgressLog "Checking exit code: $($process.ExitCode)" 708 | 709 | # Try alternative approach - direct setupprep.exe execution with Server trick 710 | Write-ProgressLog "Trying alternative approach with setupprep.exe and Server trick..." 711 | $setupPrepPath = "$extractDir\sources\setupprep.exe" 712 | if (Test-Path $setupPrepPath) { 713 | # Prepare $WINDOWS.~BT directory 714 | $btDir = "$env:SystemDrive\`$WINDOWS.~BT\Sources" 715 | if (-not (Test-Path $btDir)) { 716 | New-Item -Path $btDir -ItemType Directory -Force | Out-Null 717 | } 718 | 719 | # Copy critical files to ensure Windows.~BT has what it needs 720 | Write-ProgressLog "Copying setup files to Windows.~BT directory..." 721 | Copy-Item -Path "$extractDir\sources\*" -Destination $btDir -Force -Recurse 722 | 723 | # Create zero-byte appraiserres.dll in Windows.~BT 724 | Set-Content -Path "$btDir\appraiserres.dll" -Value "" -Force 725 | 726 | # Add additional bypass files 727 | Set-Content -Path "$btDir\Skip.cmd" -Value @" 728 | @echo off 729 | reg add HKLM\SYSTEM\Setup\MoSetup /f /v AllowUpgradesWithUnsupportedTPMorCPU /d 1 /t reg_dword 730 | reg add HKLM\SYSTEM\Setup\LabConfig /f /v BypassTPMCheck /d 1 /t reg_dword 731 | reg add HKLM\SYSTEM\Setup\LabConfig /f /v BypassSecureBootCheck /d 1 /t reg_dword 732 | reg add HKLM\SYSTEM\Setup\LabConfig /f /v BypassRAMCheck /d 1 /t reg_dword 733 | reg add HKLM\SYSTEM\Setup\LabConfig /f /v BypassStorageCheck /d 1 /t reg_dword 734 | reg add HKLM\SYSTEM\Setup\LabConfig /f /v BypassCPUCheck /d 1 /t reg_dword 735 | reg add HKLM\SYSTEM\Setup /f /v BypassComponentCheck /d 1 /t reg_dword 736 | "@ -Force 737 | 738 | # Modify the EditionID to ensure compatibility 739 | $regScript = @" 740 | Windows Registry Editor Version 5.00 741 | 742 | [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion] 743 | "EditionID_undo"="Professional" 744 | "EditionID"="Professional" 745 | "ProductName"="Windows 11 Pro" 746 | "@ 747 | Set-Content -Path "$btDir\edition.reg" -Value $regScript -Force 748 | 749 | # Create batch file to run registry changes and launch setup 750 | $setupBatchPath = "$btDir\RunSetup.cmd" 751 | 752 | $setupCommand = "setupprep.exe /product server /auto upgrade /quiet /compat ignorewarning /migratedrivers all /dynamicupdate enable /eula accept" 753 | 754 | # Add noreboot switch if automatic reboots are disabled 755 | if (-not $ALLOW_AUTOMATIC_REBOOT) { 756 | $setupCommand += " /noreboot" 757 | } 758 | 759 | $setupBatch = @" 760 | @echo off 761 | cd /d "%~dp0" 762 | call Skip.cmd 763 | regedit /s edition.reg 764 | $setupCommand 765 | "@ 766 | Set-Content -Path $setupBatchPath -Value $setupBatch -Force 767 | 768 | # Run the batch file to execute setup with all bypasses 769 | Write-ProgressLog "Launching setup with all compatibility bypasses..." 770 | Start-Process -FilePath "cmd.exe" -ArgumentList "/c $setupBatchPath" -PassThru -NoNewWindow 771 | 772 | # Wait briefly to check if it started 773 | Start-Sleep -Seconds 5 774 | 775 | # Check again if setup is running 776 | $setupStatus = Is-SetupRunning 777 | if ($setupStatus.Success) { 778 | $setupProcesses = Get-Process | Where-Object { $_.Name -match "setup|SetupHost" } 779 | foreach ($proc in $setupProcesses) { 780 | Write-ProgressLog "Setup process running: $($proc.Name) (PID: $($proc.Id))" 781 | } 782 | 783 | if ($setupStatus.Critical) { 784 | Write-ProgressLog "VERIFIED: SetupHost.exe is running via fallback method! The upgrade is confirmed to be properly underway." 785 | } else { 786 | # SetupHost is not yet running - wait for it as it's the critical indicator 787 | Write-ProgressLog "Initial setup processes started via fallback method, waiting for SetupHost.exe..." 788 | 789 | # Wait for SetupHost to appear - this is the definitive test 790 | $setupHostStarted = Wait-ForSetupHost -TimeoutSeconds 600 # Wait up to 10 minutes 791 | 792 | if ($setupHostStarted) { 793 | Write-ProgressLog "UPGRADE CONFIRMED: SetupHost.exe is running. The Windows 11 upgrade is now definitely underway." 794 | } else { 795 | Write-ProgressLog "WARNING: SetupHost.exe did not start within the expected timeframe." 796 | Write-ProgressLog "The upgrade may still proceed, but monitoring is recommended." 797 | } 798 | } 799 | 800 | Write-ProgressLog "Setup initiated via fallback method. The upgrade is now running in the background." 801 | } else { 802 | Write-ProgressLog "WARNING: Both setup methods failed to start the upgrade process." 803 | Write-ProgressLog "Please check the logs and consider running the script again." 804 | } 805 | } 806 | 807 | # Create a simple monitor script that only logs progress 808 | $monitorScript = @" 809 | @echo off 810 | echo Windows 11 upgrade monitor started at %DATE% %TIME% > "%MONITOR_LOG%" 811 | 812 | :check 813 | echo ------------------------------------------------ >> "%MONITOR_LOG%" 814 | echo Checking processes at %DATE% %TIME% >> "%MONITOR_LOG%" 815 | tasklist /fi "imagename eq setuphost.exe" >> "%MONITOR_LOG%" 816 | tasklist /fi "imagename eq setupprep.exe" >> "%MONITOR_LOG%" 817 | tasklist /fi "imagename eq setup.exe" >> "%MONITOR_LOG%" 818 | 819 | REM Check if RebootRequired registry exists (for logging only) 820 | reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" > nul 2>&1 821 | if %ERRORLEVEL% EQU 0 ( 822 | echo Reboot Required registry key found! Windows should reboot automatically. >> "%MONITOR_LOG%" 823 | ) 824 | 825 | REM Check if installation phase registry indicates readiness (for logging only) 826 | reg query "HKLM\SYSTEM\Setup" /v SystemSetupInProgress > nul 2>&1 827 | if %ERRORLEVEL% EQU 0 ( 828 | for /f "tokens=3" %%a in ('reg query "HKLM\SYSTEM\Setup" /v SystemSetupInProgress ^| find "SystemSetupInProgress"') do set SETUP_PROGRESS=%%a 829 | echo SystemSetupInProgress value: !SETUP_PROGRESS! >> "%MONITOR_LOG%" 830 | ) 831 | 832 | REM Log recent activity in setup logs 833 | echo Recent setup logs: >> "%MONITOR_LOG%" 834 | dir /a-d /od C:\$WINDOWS.~BT\Sources\Panther\*.log >> "%MONITOR_LOG%" 2>&1 835 | 836 | REM Log memory info to monitor system health 837 | echo Memory status: >> "%MONITOR_LOG%" 838 | systeminfo | find "Physical Memory" >> "%MONITOR_LOG%" 839 | echo. >> "%MONITOR_LOG%" 840 | 841 | timeout /t 300 > nul 842 | goto check 843 | "@ 844 | Set-Content -Path "$extractDir\MonitorSetup.cmd" -Value $monitorScript -Force 845 | 846 | # Start the monitor script in a hidden window 847 | Start-Process -FilePath "cmd.exe" -ArgumentList "/c $extractDir\MonitorSetup.cmd" -WindowStyle Hidden 848 | } 849 | 850 | # Clean up - delete the downloaded ISO but keep extracted files for debugging 851 | Remove-Item -Path $isoPath -Force -ErrorAction SilentlyContinue 852 | 853 | } catch { 854 | # Extract only the essential error message without the full stack trace 855 | $errorMessage = $_.Exception.Message 856 | if ($errorMessage.Length -gt 150) { 857 | $errorMessage = $errorMessage.Substring(0, 150) + "..." 858 | } 859 | 860 | # Create a clean, user-friendly error message 861 | $detailedMessage = "The Windows 11 upgrade process encountered an issue and could not continue.`nTry again or check the log file at $logFile for more details." 862 | 863 | # Try to clean up 864 | try { 865 | Remove-Item -Path $isoPath -Force -ErrorAction SilentlyContinue 866 | } catch { 867 | # Ignore cleanup errors 868 | } 869 | 870 | # Show clean error message 871 | Write-Host "ERROR: Windows 11 upgrade process failed." -ForegroundColor Red 872 | Write-Host "The Windows 11 upgrade process encountered an issue and could not continue." -ForegroundColor Yellow 873 | Write-Host "Try again or check the log file at $logFile for more details." -ForegroundColor Yellow 874 | exit 1 875 | } 876 | 877 | # Final progress information and verification 878 | if ($ALLOW_AUTOMATIC_REBOOT) { 879 | Write-ProgressLog "Windows 11 upgrade process initiated. The system will reboot automatically when the upgrade is complete." 880 | } else { 881 | Write-ProgressLog "Windows 11 upgrade process initiated. Manual reboot will be required when the upgrade preparation is complete." 882 | } 883 | Write-ProgressLog "" 884 | Write-ProgressLog "To verify the upgrade is running, check for these files:" 885 | Write-ProgressLog "- $logFile - Contains detailed progress information" 886 | Write-ProgressLog "- $MONITOR_LOG - Contains periodic process checks every 5 minutes" 887 | Write-ProgressLog "- C:\Win11_Upgrade_Completed.log - Will be created when upgrade completes" 888 | Write-ProgressLog "" 889 | Write-ProgressLog "You should also see one or more of these processes in Task Manager:" 890 | Write-ProgressLog "- SetupHost.exe - Main upgrade process" 891 | Write-ProgressLog "- setupprep.exe - Preparation process" 892 | Write-ProgressLog "- setup.exe - Initial setup launcher" 893 | Write-ProgressLog "" 894 | Write-ProgressLog "Process monitoring is active but no automatic intervention will occur." 895 | Write-ProgressLog "Windows Setup will handle the reboot process organically when ready." 896 | 897 | # One final check to make absolutely sure SetupHost is running 898 | Write-ProgressLog "Performing final verification to ensure SetupHost.exe is running..." 899 | Start-Sleep -Seconds 15 900 | 901 | $setupHost = Get-Process -Name "SetupHost" -ErrorAction SilentlyContinue 902 | if ($setupHost) { 903 | Write-ProgressLog "FINAL VERIFICATION PASSED: SetupHost.exe is running (PID: $($setupHost.Id))." 904 | Write-ProgressLog "The Windows 11 upgrade is definitely underway and proceeding properly." 905 | Write-ProgressLog "This is the CRITICAL process that confirms the upgrade will complete successfully." 906 | 907 | # Log all running setup processes for completeness 908 | $setupProcesses = Get-Process | Where-Object { $_.Name -match "setup|SetupHost" } 909 | Write-ProgressLog "All running setup processes:" 910 | foreach ($proc in $setupProcesses) { 911 | Write-ProgressLog "- $($proc.Name) (PID: $($proc.Id))" 912 | } 913 | 914 | Write-ProgressLog "UPGRADE STATUS: SUCCESS - The script has successfully initiated the Windows 11 upgrade." 915 | } else { 916 | # SetupHost is still not running - check for any setup processes 917 | $setupStatus = Is-SetupRunning 918 | if ($setupStatus.Success) { 919 | Write-ProgressLog "WARNING: Setup processes are running, but SetupHost.exe has not started yet." 920 | Write-ProgressLog "The upgrade may still proceed, but it's recommended to monitor the process." 921 | Write-ProgressLog "If needed, check the C:\$WINDOWS.~BT\Sources\Panther directory for logs." 922 | 923 | # One last attempt to wait for SetupHost 924 | Write-ProgressLog "Making final attempt to wait for SetupHost.exe to start..." 925 | $finalAttempt = Wait-ForSetupHost -TimeoutSeconds 300 # Wait 5 more minutes 926 | 927 | if ($finalAttempt) { 928 | Write-ProgressLog "SUCCESS: SetupHost.exe has finally started. The upgrade is now properly underway." 929 | } else { 930 | Write-ProgressLog "CAUTION: SetupHost.exe still not detected. The upgrade process may be abnormal." 931 | Write-ProgressLog "Please monitor the system to ensure the upgrade completes successfully." 932 | } 933 | } else { 934 | Write-ProgressLog "CRITICAL WARNING: No setup processes are running. The upgrade has likely failed to start." 935 | Write-ProgressLog "Check C:\$WINDOWS.~BT\Sources\Panther directory for setupact.log and setuperr.log files" 936 | Write-ProgressLog "You may need to run the script again or try a different approach." 937 | } 938 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Silent Windows 11 Upgrade Script 2 | 3 | This PowerShell script enables silent in-place upgrades to Windows 11, specifically designed for systems that fail compatibility checks when attempting major version upgrades through Windows Update. 4 | 5 | ## Purpose 6 | 7 | Windows 11 systems on older major versions (21H2, 22H2) often cannot upgrade to newer versions (23H2, 24H2) via Windows Update due to failing compatibility checks. This script bypasses these limitations by: 8 | 9 | - Bypassing TPM, CPU, and other hardware compatibility checks 10 | - Enabling in-place upgrades even on "unsupported" hardware 11 | - Providing a completely silent, no-interaction upgrade process 12 | - Automatically handling all aspects of the upgrade, including reboots 13 | 14 | ## Features 15 | 16 | - **Bypasses Hardware Requirements**: Overcomes TPM, CPU, RAM, SecureBoot and other compatibility blocks 17 | - **Automated ISO Handling**: Downloads or uses local ISO files (configurable) 18 | - **Dependency Management**: Automatically installs 7-Zip if not present 19 | - **Silent Operation**: Runs completely in the background with no user interaction 20 | - **Configurable Reboots**: Supports automatic or manual reboot options 21 | - **Detailed Logging**: Provides comprehensive monitoring of the upgrade process 22 | - **Cross-Version Compatibility**: Works for upgrading from Windows 10 to 11, or between Windows 11 versions 23 | 24 | ## Usage 25 | 26 | 1. **Download**: Clone or download this script to your system 27 | 2. **Configure**: Edit the parameters at the top of the script: 28 | ```powershell 29 | # ISO source (direct URL, local file, or network share) 30 | $WIN11_ISO_SOURCE = "path-to-iso-or-url" 31 | 32 | # Reboot behavior 33 | $ALLOW_AUTOMATIC_REBOOT = $true # Set to $false to prevent automatic reboots 34 | ``` 35 | 3. **Execute**: Run the script with administrative privileges 36 | ``` 37 | powershell.exe -ExecutionPolicy Bypass -File "C:\path\to\DirectWindowsUpgrade.ps1" 38 | ``` 39 | 40 | ## Process Details 41 | 42 | - The script extracts the Windows 11 ISO using 7-Zip 43 | - Registry keys are set to bypass hardware compatibility checks 44 | - Setup files are prepared with appropriate parameters 45 | - The upgrade process runs completely silently 46 | - By default, the system will reboot automatically when needed 47 | - Total upgrade process takes approximately 1.5 hours to complete 48 | 49 | ## Requirements 50 | 51 | - Windows 10 or Windows 11 system 52 | - Administrative privileges 53 | - Internet access (if using download URL) or access to Windows 11 ISO 54 | - 10GB+ free space for the upgrade process 55 | 56 | ## ISO Source 57 | 58 | For best results, use the business editions of Windows 11 with this script. You can obtain ISOs from: 59 | - Official Microsoft sources 60 | - [MassGrave Genuine Windows ISOs](https://massgrave.dev/genuine-installation-media.html) 61 | 62 | Make sure to use an ISO that contains the Windows 11 version you want to upgrade to (e.g., 23H2, 24H2). 63 | 64 | ## When to Use This Script 65 | 66 | - When Windows Update fails to offer major Windows 11 version upgrades 67 | - When systems have "unsupported" hardware that blocks updates 68 | - When you need to perform silent, unattended upgrades 69 | - For bulk upgrades across multiple systems with similar hardware 70 | 71 | ## Logs and Monitoring 72 | 73 | The script generates several log files to help monitor progress: 74 | - `C:\Win11_Upgrade_Progress.log` - Main progress log 75 | - `C:\Win11_Monitor.log` - Process monitoring log 76 | - `C:\Win11_Upgrade_Completed.log` - Created upon successful completion 77 | 78 | ## Customization 79 | 80 | All configurable parameters are at the top of the script: 81 | - `$WIN11_ISO_SOURCE` - Source location for Windows 11 ISO 82 | - `$WORKING_DIR` - Main working directory 83 | - `$TEMP_DIR` - Temporary directory for downloads 84 | - `$LOG_FILE` - Main log file path 85 | - `$MONITOR_LOG` - Process monitor log path 86 | - `$ALLOW_AUTOMATIC_REBOOT` - Enable/disable automatic reboots 87 | 88 | ## Attribution 89 | 90 | This script combines techniques from multiple sources, including AveYo's MediaCreationTool project, for maximum compatibility with different Windows 11 versions and hardware configurations. --------------------------------------------------------------------------------