Private/Get-WUWindows11ISO-PS51.ps1
|
function Get-WUWindows11ISO { <# .SYNOPSIS Downloads the latest Windows 11 ISO from Microsoft with PowerShell 5.1 compatibility .DESCRIPTION This function downloads the latest Windows 11 ISO file from Microsoft using multiple methods including Fido, UUP dump, and the official Media Creation Tool. It supports multiple languages and editions, with automatic fallback mechanisms and enhanced reliability features including retry logic and PowerShell 5.1 compatibility. .PARAMETER OutputPath Directory where the ISO file should be saved. Defaults to current directory. .PARAMETER Language Language code for the Windows 11 ISO (e.g., 'en-us', 'de-de', 'fr-fr'). Defaults to system language or 'en-us' if system language not supported. .PARAMETER Edition Windows 11 edition to download. Defaults to 'Professional'. Valid options: Home, Professional, Education, Enterprise .PARAMETER Architecture System architecture. Defaults to 'x64'. Valid options: x64, arm64 .PARAMETER Method Download method to use. If not specified, will try methods in order of preference. Valid options: Fido, UUP, MediaCreationTool, Auto .PARAMETER SkipVerification Skip file verification after download .PARAMETER Force Overwrite existing ISO files .PARAMETER MaxRetries Maximum number of retry attempts for failed downloads. Defaults to 3. .PARAMETER RetryDelay Delay in seconds between retry attempts. Defaults to 10. .EXAMPLE Get-WUWindows11ISO -OutputPath "C:\ISOs" Downloads Windows 11 Professional x64 in system language to C:\ISOs .EXAMPLE Get-WUWindows11ISO -Language "de-de" -Edition "Enterprise" -Method "Fido" Downloads Windows 11 Enterprise x64 in German using Fido method .NOTES Requires internet connection and sufficient disk space (5+ GB) Enhanced for PowerShell 5.1 compatibility with improved retry logic Some methods may require PowerShell to be run as Administrator #> [CmdletBinding()] param( [Parameter()] [string]$OutputPath = (Get-Location).Path, [Parameter()] [string]$Language, [Parameter()] [ValidateSet('Home', 'Professional', 'Education', 'Enterprise')] [string]$Edition = 'Professional', [Parameter()] [ValidateSet('x64', 'arm64')] [string]$Architecture = 'x64', [Parameter()] [ValidateSet('Fido', 'UUP', 'MediaCreationTool', 'Auto')] [string]$Method = 'Auto', [Parameter()] [switch]$SkipVerification, [Parameter()] [switch]$Force, [Parameter()] [int]$MaxRetries = 3, [Parameter()] [int]$RetryDelay = 10 ) # PowerShell 5.1 compatible TLS setup try { Write-WULog "Configuring TLS for PowerShell 5.1 compatibility" -Level Info [System.Net.ServicePointManager]::SecurityProtocol = 'Tls12' Write-WULog "TLS 1.2 configured successfully" -Level Info } catch { Write-WULog "Failed to configure TLS 1.2: $($_.Exception.Message)" -Level Warning try { # Fallback method for older systems [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 } catch { Write-WULog "TLS configuration fallback also failed. Downloads may fail." -Level Error } } Write-WULog "Starting Windows 11 ISO download process (Enhanced PS 5.1 compatible version)" -Level Info # Validate and create output directory if (-not (Test-Path $OutputPath)) { try { New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null Write-WULog "Created output directory: $OutputPath" -Level Info } catch { Write-Error "Failed to create output directory: $($_.Exception.Message)" return $null } } # Auto-detect system language if not specified if (-not $Language) { $Language = Get-WUSystemLanguageEnhanced Write-WULog "Auto-detected system language: $Language" -Level Info } # Define download methods in order of preference $downloadMethods = if ($Method -eq 'Auto') { @('Fido', 'MediaCreationTool', 'UUP') } else { @($Method) } $isoFile = $null $lastError = $null $globalRetryCount = 0 $maxGlobalRetries = $MaxRetries # Global retry loop for all methods while ($globalRetryCount -lt $maxGlobalRetries -and (-not $isoFile -or -not (Test-Path $isoFile))) { $globalRetryCount++ if ($globalRetryCount -gt 1) { Write-WULog "Global retry attempt $globalRetryCount of $maxGlobalRetries" -Level Info Start-Sleep -Seconds $RetryDelay } foreach ($currentMethod in $downloadMethods) { Write-WULog "Attempting download using method: $currentMethod (Global attempt: $globalRetryCount)" -Level Info $methodRetryCount = 0 $methodSuccess = $false # Method-specific retry loop while ($methodRetryCount -lt $MaxRetries -and -not $methodSuccess) { $methodRetryCount++ if ($methodRetryCount -gt 1) { Write-WULog "Method $currentMethod retry attempt $methodRetryCount of $MaxRetries" -Level Info Start-Sleep -Seconds $RetryDelay } try { switch ($currentMethod) { 'Fido' { $isoFile = Invoke-FidoDownloadEnhanced -OutputPath $OutputPath -Language $Language -Edition $Edition -Architecture $Architecture -Force:$Force } 'UUP' { $isoFile = Invoke-UUPDownloadEnhanced -OutputPath $OutputPath -Language $Language -Edition $Edition -Architecture $Architecture -Force:$Force } 'MediaCreationTool' { $isoFile = Invoke-MediaCreationToolDownloadEnhanced -OutputPath $OutputPath -Language $Language -Edition $Edition -Architecture $Architecture -Force:$Force } } if ($isoFile -and (Test-Path $isoFile)) { Write-WULog "Successfully downloaded Windows 11 ISO using $currentMethod method: $isoFile" -Level Info $methodSuccess = $true break } } catch { $lastError = $_.Exception Write-WULog "Method $currentMethod attempt $methodRetryCount failed: $($_.Exception.Message)" -Level Warning # Check for specific Microsoft server restrictions if ($_.Exception.Message -match "403|forbidden|rate.?limit|too.?many.?requests") { Write-WULog "Detected Microsoft server restrictions. Waiting longer before retry..." -Level Warning Start-Sleep -Seconds ($RetryDelay * 2) } } } if ($methodSuccess) { break } } if ($isoFile -and (Test-Path $isoFile)) { break } if ($globalRetryCount -lt $maxGlobalRetries) { Write-WULog "All methods failed in attempt $globalRetryCount. Will retry all methods after delay..." -Level Warning } } if (-not $isoFile -or -not (Test-Path $isoFile)) { $errorMessage = "All download methods failed after $globalRetryCount global attempts." if ($lastError) { $errorMessage += " Last error: $($lastError.Message)" } Write-Error $errorMessage return $null } # Verify downloaded ISO file if (-not $SkipVerification) { Write-WULog "Verifying downloaded ISO file..." -Level Info if (-not (Test-ISOFileEnhanced -Path $isoFile)) { Write-Error "Downloaded ISO file failed verification" return $null } Write-WULog "ISO file verification passed" -Level Info } # Return the downloaded ISO file information $isoInfo = Get-Item $isoFile $result = [PSCustomObject]@{ Path = $isoInfo.FullName Name = $isoInfo.Name Size = [math]::Round($isoInfo.Length / 1GB, 2) Language = $Language Edition = $Edition Architecture = $Architecture Method = $currentMethod DownloadDate = Get-Date RetryCount = $globalRetryCount } Write-WULog "Windows 11 ISO download completed successfully after $globalRetryCount global attempts" -Level Info return $result } #region Enhanced Helper Functions function Get-WUSystemLanguageEnhanced { <# .SYNOPSIS Gets the system language code suitable for Windows ISO downloads (Enhanced) #> try { # Get system locale with multiple methods for reliability $systemLocale = $null try { $systemLocale = Get-Culture } catch { try { $systemLocale = [System.Globalization.CultureInfo]::CurrentCulture } catch { Write-WULog "Could not determine system culture, using en-us" -Level Warning return 'en-us' } } $languageTag = $systemLocale.Name.ToLower() # Enhanced language mapping with more comprehensive coverage $languageMap = @{ 'en-us' = 'en-us'; 'en-gb' = 'en-gb'; 'en-ca' = 'en-us'; 'en-au' = 'en-us' 'de-de' = 'de-de'; 'de-at' = 'de-de'; 'de-ch' = 'de-de' 'fr-fr' = 'fr-fr'; 'fr-ca' = 'fr-fr'; 'fr-be' = 'fr-fr'; 'fr-ch' = 'fr-fr' 'es-es' = 'es-es'; 'es-mx' = 'es-es'; 'es-ar' = 'es-es'; 'es-co' = 'es-es' 'it-it' = 'it-it'; 'it-ch' = 'it-it' 'pt-br' = 'pt-br'; 'pt-pt' = 'pt-pt' 'ja-jp' = 'ja-jp'; 'ko-kr' = 'ko-kr' 'zh-cn' = 'zh-cn'; 'zh-tw' = 'zh-tw'; 'zh-hk' = 'zh-tw'; 'zh-sg' = 'zh-cn' 'nl-nl' = 'nl-nl'; 'nl-be' = 'nl-nl' 'sv-se' = 'sv-se'; 'da-dk' = 'da-dk'; 'no-no' = 'nb-no'; 'nb-no' = 'nb-no' 'fi-fi' = 'fi-fi'; 'pl-pl' = 'pl-pl'; 'ru-ru' = 'ru-ru' 'cs-cz' = 'cs-cz'; 'hu-hu' = 'hu-hu'; 'tr-tr' = 'tr-tr' 'ar-sa' = 'ar-sa'; 'he-il' = 'he-il'; 'th-th' = 'th-th' } if ($languageMap.ContainsKey($languageTag)) { return $languageMap[$languageTag] } # Try just the language part if full locale not found $languageOnly = $languageTag.Split('-')[0] $fallbackMap = @{ 'en' = 'en-us'; 'de' = 'de-de'; 'fr' = 'fr-fr'; 'es' = 'es-es' 'it' = 'it-it'; 'pt' = 'pt-br'; 'ja' = 'ja-jp'; 'ko' = 'ko-kr' 'zh' = 'zh-cn'; 'nl' = 'nl-nl'; 'sv' = 'sv-se'; 'da' = 'da-dk' 'no' = 'nb-no'; 'fi' = 'fi-fi'; 'pl' = 'pl-pl'; 'ru' = 'ru-ru' 'cs' = 'cs-cz'; 'hu' = 'hu-hu'; 'tr' = 'tr-tr' 'ar' = 'ar-sa'; 'he' = 'he-il'; 'th' = 'th-th' } if ($fallbackMap.ContainsKey($languageOnly)) { return $fallbackMap[$languageOnly] } Write-WULog "System language '$languageTag' not supported, defaulting to 'en-us'" -Level Warning return 'en-us' } catch { Write-WULog "Failed to detect system language: $($_.Exception.Message)" -Level Warning return 'en-us' } } function Invoke-FidoDownloadEnhanced { <# .SYNOPSIS Downloads Windows 11 ISO using the Fido PowerShell script (Enhanced with PS 5.1 compatibility) #> param( [string]$OutputPath, [string]$Language, [string]$Edition, [string]$Architecture, [switch]$Force ) Write-WULog "Starting enhanced Fido download method" -Level Info # Download Fido script with retry logic $fidoPath = Join-Path $OutputPath "Fido.ps1" $fidoUrl = "https://github.com/pbatard/Fido/raw/master/Fido.ps1" $fidoDownloadSuccess = $false $fidoRetryCount = 0 $maxFidoRetries = 3 while ($fidoRetryCount -lt $maxFidoRetries -and -not $fidoDownloadSuccess) { $fidoRetryCount++ try { Write-WULog "Downloading Fido script (attempt $fidoRetryCount): $fidoUrl" -Level Info # Use more robust download with progress and timeout $webClient = New-Object System.Net.WebClient $webClient.DownloadFile($fidoUrl, $fidoPath) if (Test-Path $fidoPath) { $fidoSize = (Get-Item $fidoPath).Length if ($fidoSize -gt 1000) { # Basic size check $fidoDownloadSuccess = $true Write-WULog "Fido script downloaded successfully ($fidoSize bytes)" -Level Info } else { throw "Downloaded Fido script appears incomplete" } } else { throw "Fido script file not found after download" } } catch { Write-WULog "Fido download attempt $fidoRetryCount failed: $($_.Exception.Message)" -Level Warning if ($fidoRetryCount -lt $maxFidoRetries) { Start-Sleep -Seconds 5 } } } if (-not $fidoDownloadSuccess) { throw "Failed to download Fido script after $maxFidoRetries attempts" } try { # Prepare Fido parameters with enhanced mapping $editionMap = @{ 'Home' = 'Home' 'Professional' = 'Pro' 'Education' = 'Education' 'Enterprise' = 'Enterprise' } $fidoEdition = if ($editionMap.ContainsKey($Edition)) { $editionMap[$Edition] } else { 'Pro' } $fidoParams = @{ Win = '11' Rel = 'Latest' Ed = $fidoEdition Lang = $Language Arch = $Architecture GetUrl = $false } Write-WULog "Executing Fido with enhanced parameters: Win=$($fidoParams.Win), Rel=$($fidoParams.Rel), Ed=$($fidoParams.Ed), Lang=$($fidoParams.Lang), Arch=$($fidoParams.Arch)" -Level Info # Execute Fido script with better error handling $previousLocation = Get-Location Set-Location $OutputPath try { # Check for existing ISO files before download $preExistingISOs = Get-ChildItem -Path $OutputPath -Filter "*.iso" -ErrorAction SilentlyContinue # Execute Fido with enhanced error capture $fidoOutput = & $fidoPath @fidoParams 2>&1 if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) { throw "Fido exited with code: $LASTEXITCODE. Output: $fidoOutput" } # Enhanced ISO file detection Start-Sleep -Seconds 2 # Allow file system to update $newIsoFiles = Get-ChildItem -Path $OutputPath -Filter "*.iso" -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike "*windows10*" -and $_.Name -like "*windows*11*" } | Sort-Object LastWriteTime -Descending # Filter out pre-existing ISOs if ($preExistingISOs) { $newIsoFiles = $newIsoFiles | Where-Object { $newFile = $_ -not ($preExistingISOs | Where-Object { $_.Name -eq $newFile.Name }) } } if ($newIsoFiles) { $isoFile = $newIsoFiles[0].FullName Write-WULog "Enhanced Fido download completed: $isoFile" -Level Info return $isoFile } else { # Fallback: look for any recent Windows 11 ISO $allIsos = Get-ChildItem -Path $OutputPath -Filter "*win*11*.iso" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending if ($allIsos) { $isoFile = $allIsos[0].FullName Write-WULog "Found potential Windows 11 ISO: $isoFile" -Level Info return $isoFile } throw "No Windows 11 ISO file found after Fido execution. Output: $fidoOutput" } } finally { Set-Location $previousLocation } } catch { Write-WULog "Enhanced Fido execution failed: $($_.Exception.Message)" -Level Error throw } finally { # Clean up Fido script if (Test-Path $fidoPath) { try { Remove-Item $fidoPath -Force -ErrorAction SilentlyContinue Write-WULog "Fido script cleanup completed" -Level Info } catch { Write-WULog "Could not clean up Fido script: $($_.Exception.Message)" -Level Warning } } } } function Invoke-UUPDownloadEnhanced { <# .SYNOPSIS Downloads Windows 11 ISO using UUP dump method (Enhanced placeholder) #> param( [string]$OutputPath, [string]$Language, [string]$Edition, [string]$Architecture, [switch]$Force ) Write-WULog "Enhanced UUP download method - currently not implemented" -Level Warning throw "UUP download method requires specialized UUP API implementation" } function Invoke-MediaCreationToolDownloadEnhanced { <# .SYNOPSIS Downloads Windows 11 ISO using Microsoft's Media Creation Tool (Enhanced) #> param( [string]$OutputPath, [string]$Language, [string]$Edition, [string]$Architecture, [switch]$Force ) Write-WULog "Starting enhanced Media Creation Tool download method" -Level Info # Download Media Creation Tool with retry logic $mctPath = Join-Path $OutputPath "MediaCreationToolW11.exe" $mctUrl = "https://go.microsoft.com/fwlink/?linkid=2156295" $mctDownloadSuccess = $false $mctRetryCount = 0 $maxMctRetries = 3 while ($mctRetryCount -lt $maxMctRetries -and -not $mctDownloadSuccess) { $mctRetryCount++ try { Write-WULog "Downloading Media Creation Tool (attempt $mctRetryCount): $mctUrl" -Level Info # Use WebClient for better control and PS 5.1 compatibility $webClient = New-Object System.Net.WebClient $webClient.DownloadFile($mctUrl, $mctPath) if (Test-Path $mctPath) { $mctSize = (Get-Item $mctPath).Length if ($mctSize -gt 1000000) { # Should be several MB $mctDownloadSuccess = $true Write-WULog "Media Creation Tool downloaded successfully ($([math]::Round($mctSize/1MB, 2)) MB)" -Level Info } else { throw "Downloaded Media Creation Tool appears incomplete" } } else { throw "Media Creation Tool file not found after download" } } catch { Write-WULog "MCT download attempt $mctRetryCount failed: $($_.Exception.Message)" -Level Warning if ($mctRetryCount -lt $maxMctRetries) { Start-Sleep -Seconds 10 } } } if (-not $mctDownloadSuccess) { throw "Failed to download Media Creation Tool after $maxMctRetries attempts" } try { Write-WULog "Media Creation Tool automated execution is complex and may require user interaction" -Level Warning Write-WULog "For fully automated ISO download, Fido method is recommended" -Level Info # Note: MCT typically requires user interaction for ISO creation # This is a simplified implementation that downloads the tool # In practice, MCT may require GUI interaction for ISO creation throw "Media Creation Tool requires manual interaction for ISO creation. Use Fido method for automation." } catch { Write-WULog "Enhanced Media Creation Tool execution failed: $($_.Exception.Message)" -Level Error throw } finally { # Clean up Media Creation Tool if (Test-Path $mctPath) { try { Remove-Item $mctPath -Force -ErrorAction SilentlyContinue Write-WULog "Media Creation Tool cleanup completed" -Level Info } catch { Write-WULog "Could not clean up Media Creation Tool: $($_.Exception.Message)" -Level Warning } } } } function Test-ISOFileEnhanced { <# .SYNOPSIS Enhanced verification that a file is a valid Windows 11 ISO file #> param( [Parameter(Mandatory)] [string]$Path ) try { if (-not (Test-Path $Path)) { Write-WULog "ISO file does not exist: $Path" -Level Error return $false } $file = Get-Item $Path Write-WULog "Verifying ISO file: $($file.Name) ($([math]::Round($file.Length / 1GB, 2)) GB)" -Level Info # Enhanced size validation for Windows 11 if ($file.Length -lt 3.5GB) { Write-WULog "ISO file too small for Windows 11: $([math]::Round($file.Length / 1GB, 2)) GB (minimum ~3.5GB)" -Level Warning return $false } if ($file.Length -gt 8GB) { Write-WULog "ISO file larger than expected: $([math]::Round($file.Length / 1GB, 2)) GB (maximum ~8GB)" -Level Warning } # Enhanced file signature verification try { $buffer = New-Object byte[] 4096 $stream = [System.IO.File]::OpenRead($Path) $bytesRead = $stream.Read($buffer, 0, 4096) $stream.Close() if ($bytesRead -lt 4096) { Write-WULog "Could not read sufficient bytes for verification" -Level Warning return $false } # Check for standard ISO signatures $hasISOSignature = $false # Look for "CD001" at various offsets (ISO 9660) for ($offset = 32768; $offset -lt 40000; $offset += 2048) { if ($offset + 5 -lt $buffer.Length) { $signature = [System.Text.Encoding]::ASCII.GetString($buffer, ($offset % $buffer.Length), 5) if ($signature -eq "CD001") { $hasISOSignature = $true break } } } # Alternative check for UDF signatures if (-not $hasISOSignature) { $udfPatterns = @("BEA01", "NSR02", "NSR03") foreach ($pattern in $udfPatterns) { $patternBytes = [System.Text.Encoding]::ASCII.GetBytes($pattern) for ($i = 0; $i -le ($buffer.Length - $patternBytes.Length); $i++) { $match = $true for ($j = 0; $j -lt $patternBytes.Length; $j++) { if ($buffer[$i + $j] -ne $patternBytes[$j]) { $match = $false break } } if ($match) { $hasISOSignature = $true break } } if ($hasISOSignature) { break } } } if ($hasISOSignature) { Write-WULog "ISO file signature verification passed" -Level Info } else { Write-WULog "No standard ISO signature found, but file may still be valid" -Level Warning } return $true } catch { Write-WULog "File signature verification failed: $($_.Exception.Message)" -Level Warning # Don't fail completely on signature check errors return $true } } catch { Write-WULog "Enhanced ISO file verification failed: $($_.Exception.Message)" -Level Error return $false } } #endregion Enhanced Helper Functions |