├── .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.
--------------------------------------------------------------------------------