dist/temp/WindowsUpdateTools/Private/Test-WUWindows11Compatibility.ps1
|
function Test-WUWindows11Compatibility { <# .SYNOPSIS Tests Windows 11 upgrade compatibility requirements. .DESCRIPTION Comprehensive Windows 11 compatibility assessment checking all major requirements including CPU, TPM, Secure Boot, UEFI, memory, storage, and more. Also checks for existing Microsoft compatibility holds via registry. .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $compatibility = Test-WUWindows11Compatibility -LogPath "C:\Logs\wu.log" .NOTES This is a private function used internally by the WindowsUpdateTools module. Returns detailed Windows 11 compatibility assessment. #> [CmdletBinding()] param( [string]$LogPath ) Write-WULog -Message "Starting Windows 11 compatibility assessment" -LogPath $LogPath # Initialize results object $results = [PSCustomObject]@{ Compatible = $true OverallAssessment = "Compatible" Checks = @{} FailedChecks = @() WarningChecks = @() CompatibilityHolds = @() SystemInfo = @{} Issues = @() ErrorMessage = $null } try { # Get current OS info for context $osInfo = Get-CimInstance -ClassName Win32_OperatingSystem $currentBuild = $osInfo.BuildNumber Write-WULog -Message "Current OS: $($osInfo.Caption) Build $currentBuild" -LogPath $LogPath # Check for existing Microsoft compatibility holds first Write-WULog -Message "Checking for existing Microsoft compatibility holds..." -LogPath $LogPath $compatibilityHolds = Test-WUCompatibilityHolds -LogPath $LogPath if ($compatibilityHolds.Count -gt 0) { $results.CompatibilityHolds = $compatibilityHolds $results.Compatible = $false $results.OverallAssessment = "Blocked by Microsoft" foreach ($hold in $compatibilityHolds) { $results.Issues += "Microsoft compatibility hold: $hold" } } # 1. Architecture Check (64-bit requirement) Write-WULog -Message "Checking system architecture..." -LogPath $LogPath $archCheck = Test-WUArchitecture -LogPath $LogPath $results.Checks["Architecture"] = $archCheck if (-not $archCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Architecture" $results.Issues += $archCheck.Issue } # 2. UEFI/Boot Mode Check Write-WULog -Message "Checking boot mode (UEFI requirement)..." -LogPath $LogPath $bootCheck = Test-WUBootMode -LogPath $LogPath $results.Checks["BootMode"] = $bootCheck if (-not $bootCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "BootMode" $results.Issues += $bootCheck.Issue } # 3. CPU Compatibility Check Write-WULog -Message "Checking CPU compatibility..." -LogPath $LogPath $cpuCheck = Test-WUCPUCompatibility -LogPath $LogPath $results.Checks["CPU"] = $cpuCheck if (-not $cpuCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "CPU" $results.Issues += $cpuCheck.Issue } # 4. Memory Check (4GB minimum) Write-WULog -Message "Checking memory requirements..." -LogPath $LogPath $memoryCheck = Test-WUMemoryRequirement -LogPath $LogPath $results.Checks["Memory"] = $memoryCheck if (-not $memoryCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Memory" $results.Issues += $memoryCheck.Issue } # 5. Storage Check (64GB minimum) Write-WULog -Message "Checking storage requirements..." -LogPath $LogPath $storageCheck = Test-WUStorageRequirement -LogPath $LogPath $results.Checks["Storage"] = $storageCheck if (-not $storageCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Storage" $results.Issues += $storageCheck.Issue } # 6. TPM Check (2.0 requirement) Write-WULog -Message "Checking TPM requirements..." -LogPath $LogPath $tpmCheck = Test-WUTPMRequirement -LogPath $LogPath $results.Checks["TPM"] = $tpmCheck if (-not $tpmCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "TPM" $results.Issues += $tpmCheck.Issue } # 7. Secure Boot Check Write-WULog -Message "Checking Secure Boot requirements..." -LogPath $LogPath $secureBootCheck = Test-WUSecureBootRequirement -LogPath $LogPath $results.Checks["SecureBoot"] = $secureBootCheck if (-not $secureBootCheck.Passed) { # Secure Boot can be enabled, so this might be a warning rather than failure if ($secureBootCheck.CanBeEnabled) { $results.WarningChecks += "SecureBoot" $results.Issues += "Warning: " + $secureBootCheck.Issue } else { $results.Compatible = $false $results.FailedChecks += "SecureBoot" $results.Issues += $secureBootCheck.Issue } } # 8. GPT Disk Check Write-WULog -Message "Checking disk partitioning (GPT requirement)..." -LogPath $LogPath $diskCheck = Test-WUDiskPartitioning -LogPath $LogPath $results.Checks["DiskPartitioning"] = $diskCheck if (-not $diskCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "DiskPartitioning" $results.Issues += $diskCheck.Issue } # 9. DirectX 12 Check Write-WULog -Message "Checking DirectX 12 requirements..." -LogPath $LogPath $dxCheck = Test-WUDirectXRequirement -LogPath $LogPath $results.Checks["DirectX12"] = $dxCheck if (-not $dxCheck.Passed) { if ($dxCheck.IsWarning) { $results.WarningChecks += "DirectX12" $results.Issues += "Warning: " + $dxCheck.Issue } else { $results.Compatible = $false $results.FailedChecks += "DirectX12" $results.Issues += $dxCheck.Issue } } # 10. Internet Connectivity Check (for updates) Write-WULog -Message "Checking internet connectivity..." -LogPath $LogPath $internetCheck = Test-WUInternetConnectivity -LogPath $LogPath $results.Checks["InternetConnectivity"] = $internetCheck if (-not $internetCheck.Passed) { $results.WarningChecks += "InternetConnectivity" $results.Issues += "Warning: " + $internetCheck.Issue } # Determine overall assessment if ($results.CompatibilityHolds.Count -gt 0) { $results.OverallAssessment = "Blocked by Microsoft compatibility hold" } elseif ($results.FailedChecks.Count -gt 0) { $results.OverallAssessment = "Not compatible - $($results.FailedChecks.Count) requirement(s) failed" $results.Compatible = $false } elseif ($results.WarningChecks.Count -gt 0) { $results.OverallAssessment = "Compatible with warnings - $($results.WarningChecks.Count) item(s) need attention" } else { $results.OverallAssessment = "Fully compatible" } # Log summary Write-WULog -Message "Windows 11 compatibility assessment completed:" -LogPath $LogPath Write-WULog -Message " Overall: $($results.OverallAssessment)" -LogPath $LogPath Write-WULog -Message " Failed checks: $($results.FailedChecks.Count)" -LogPath $LogPath Write-WULog -Message " Warning checks: $($results.WarningChecks.Count)" -LogPath $LogPath Write-WULog -Message " Compatibility holds: $($results.CompatibilityHolds.Count)" -LogPath $LogPath if ($results.FailedChecks.Count -gt 0) { Write-WULog -Message "Failed requirements: $($results.FailedChecks -join ', ')" -Level Warning -LogPath $LogPath } } catch { $results.ErrorMessage = $_.Exception.Message Write-WULog -Message "Error during Windows 11 compatibility assessment: $($_.Exception.Message)" -Level Error -LogPath $LogPath } return $results } function Test-WUCompatibilityHolds { <# .SYNOPSIS Checks for Microsoft-imposed compatibility holds. .DESCRIPTION Checks registry for Microsoft compatibility holds that would block Windows 11 upgrade. Only treats actual blocking reasons as holds, ignoring "None" values. Handles both string and string array registry values. #> param([string]$LogPath) $holds = @() try { # Check various Windows versions for compatibility holds $windowsVersions = @("Windows 11", "22H2", "21H2", "23H2", "24H2") foreach ($version in $windowsVersions) { $regPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\TargetVersionUpgradeExperienceIndicators\$version" if (Test-Path $regPath) { $redReason = Get-ItemProperty -Path $regPath -Name "RedReason" -ErrorAction SilentlyContinue if ($redReason -and $redReason.RedReason) { # Handle both string and string array values $reasonValues = @() if ($redReason.RedReason -is [Array]) { # Registry value is REG_MULTI_SZ (string array) $reasonValues = $redReason.RedReason Write-WULog -Message "Found registry array for $version with $($reasonValues.Count) values" -LogPath $LogPath } else { # Registry value is REG_SZ (single string) $reasonValues = @($redReason.RedReason.ToString()) } # Check each value to see if it's actually a blocking reason $actualBlocks = @() foreach ($reasonValue in $reasonValues) { $cleanValue = $reasonValue.ToString().Trim() if ($cleanValue -ne "None" -and $cleanValue -ne "" -and $cleanValue -ne $null) { $actualBlocks += $cleanValue } } if ($actualBlocks.Count -gt 0) { foreach ($block in $actualBlocks) { $holds += "Version $version`: $block" Write-WULog -Message "Found compatibility hold for $version`: $block" -Level Warning -LogPath $LogPath } } else { Write-WULog -Message "Found registry entry for $version but all values are 'None' or empty (no actual hold)" -LogPath $LogPath } } } } if ($holds.Count -eq 0) { Write-WULog -Message "No Microsoft compatibility holds found" -LogPath $LogPath } } catch { Write-WULog -Message "Error checking compatibility holds: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $holds } function Test-WUArchitecture { <# .SYNOPSIS Tests CPU architecture requirements (64-bit). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { $cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object -First 1 $os = Get-CimInstance -ClassName Win32_OperatingSystem $result.Value = $cpu.Architecture $result.Details["CPUArchitecture"] = $cpu.Architecture $result.Details["OSArchitecture"] = $os.OSArchitecture # Check for 64-bit capability if ($cpu.Architecture -eq 9) { # 9 = x64 $result.Passed = $true Write-WULog -Message "Architecture check passed: x64" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires 64-bit (x64) processor architecture" Write-WULog -Message "Architecture check failed: $($cpu.Architecture)" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine system architecture" Write-WULog -Message "Error checking architecture: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUBootMode { <# .SYNOPSIS Tests UEFI boot mode requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Check firmware type $firmwareType = $env:firmware_type $result.Value = $firmwareType if ($firmwareType -eq "UEFI") { $result.Passed = $true Write-WULog -Message "Boot mode check passed: UEFI" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires UEFI firmware (Legacy BIOS not supported)" Write-WULog -Message "Boot mode check failed: $firmwareType" -LogPath $LogPath } $result.Details["FirmwareType"] = $firmwareType } catch { $result.Issue = "Unable to determine boot mode" Write-WULog -Message "Error checking boot mode: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUCPUCompatibility { <# .SYNOPSIS Tests CPU compatibility for Windows 11 using simple generation-based logic. .DESCRIPTION Determines CPU compatibility by parsing the CPU name to extract generation. Blocks Intel CPUs older than 8th generation and unsupported AMD architectures. Uses reliable name-based detection instead of inconsistent WMI properties. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Get CPU information $cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object -First 1 $result.Value = $cpu.Name $result.Details["CPUName"] = $cpu.Name $result.Details["Manufacturer"] = $cpu.Manufacturer $result.Details["Cores"] = $cpu.NumberOfCores $result.Details["LogicalProcessors"] = $cpu.NumberOfLogicalProcessors $result.Details["MaxClockSpeed"] = $cpu.MaxClockSpeed $result.Details["Architecture"] = $cpu.Architecture $result.Details["AddressWidth"] = $cpu.AddressWidth Write-WULog -Message "CPU: $($cpu.Name), Manufacturer: $($cpu.Manufacturer)" -LogPath $LogPath # Check basic hardware requirements first $issues = @() # 64-bit requirement if ($null -eq $cpu.AddressWidth -or $cpu.AddressWidth -ne 64) { $issues += "CPU must support 64-bit addressing (found: $($cpu.AddressWidth)-bit)" } # Speed requirement (1 GHz minimum) if ($null -eq $cpu.MaxClockSpeed -or $cpu.MaxClockSpeed -le 1000) { $issues += "CPU must be faster than 1 GHz (found: $($cpu.MaxClockSpeed) MHz)" } # Core count requirement (2 logical cores minimum) if ($null -eq $cpu.NumberOfLogicalProcessors -or $cpu.NumberOfLogicalProcessors -lt 2) { $issues += "CPU must have at least 2 logical cores (found: $($cpu.NumberOfLogicalProcessors))" } # CPU Generation/Model Compatibility Check $cpuSupported = $true $blockReason = "" $detectedGeneration = "Unknown" $cpuName = $cpu.Name if ($cpu.Manufacturer -like "*Intel*" -or $cpu.Manufacturer -eq "GenuineIntel") { Write-WULog -Message "Checking Intel CPU compatibility..." -LogPath $LogPath # Method 1: Modern naming with "Nth Gen" in the name if ($cpuName -match "(\d+)th Gen") { $generation = [int]$matches[1] $detectedGeneration = "${generation}th Generation" if ($generation -lt 8) { $cpuSupported = $false $blockReason = "Intel ${generation}th generation CPUs not supported (requires 8th generation or newer)" } } # Method 2: Older naming pattern (i3/i5/i7/i9-XXXX) - More robust approach elseif ($cpuName -match "i[3579]-(\d{4,5})[A-Z]*") { $modelNumber = [int]$matches[1] # Use numeric comparison to determine generation if ($modelNumber -ge 10000) { # 5-digit numbers: 10xxx, 11xxx, 12xxx, etc. $generation = [Math]::Floor($modelNumber / 1000) } else { # 4-digit numbers: 1xxx, 2xxx, 3xxx, etc. $generation = [Math]::Floor($modelNumber / 1000) } $detectedGeneration = "${generation}th Generation (model: $modelNumber)" if ($generation -lt 8) { $cpuSupported = $false $blockReason = "Intel ${generation}th generation CPUs not supported (requires 8th generation or newer)" } } # Method 3: Very old Intel architectures elseif ($cpuName -match "(Core 2|Pentium 4|Pentium D|Celeron M|Atom)") { $architecture = $matches[1] $cpuSupported = $false $blockReason = "Intel $architecture architecture not supported for Windows 11" $detectedGeneration = "Legacy Intel" } # Method 4: Other Pentium/Celeron (check for modern variants) elseif ($cpuName -match "(Pentium|Celeron)") { if ($cpuName -match "(Pentium Gold|Celeron G\d{4})") { $detectedGeneration = "Modern Pentium/Celeron (likely supported)" } else { $cpuSupported = $false $blockReason = "Older Pentium/Celeron processors not supported for Windows 11" $detectedGeneration = "Legacy Pentium/Celeron" } } # Method 5: Fallback - couldn't determine generation else { $detectedGeneration = "Unknown Intel generation" Write-WULog -Message "WARNING: Could not determine Intel CPU generation from name: $cpuName" -Level Warning -LogPath $LogPath } } elseif ($cpu.Manufacturer -like "*AMD*" -or $cpu.Manufacturer -eq "AuthenticAMD") { Write-WULog -Message "Checking AMD CPU compatibility..." -LogPath $LogPath # AMD Ryzen series if ($cpuName -match "Ryzen.*(\d)(\d{3})") { $series = [int]$matches[1] $detectedGeneration = "AMD Ryzen ${series}000 series" # Most Ryzen 2000+ series are supported, some Ryzen 1000 models too if ($series -eq 1) { Write-WULog -Message "AMD Ryzen 1000 series - some models may not be supported" -Level Warning -LogPath $LogPath $detectedGeneration += " (verify specific model compatibility)" } } # AMD FX series (older, not supported) elseif ($cpuName -match "FX-(\d)(\d{3})") { $cpuSupported = $false $blockReason = "AMD FX series processors not supported for Windows 11" $detectedGeneration = "AMD FX series" } # Other older AMD architectures elseif ($cpuName -match "(Athlon|Phenom|A[4-9]-\d{4})") { $architecture = $matches[1] $cpuSupported = $false $blockReason = "AMD $architecture architecture not supported for Windows 11" $detectedGeneration = "Legacy AMD" } else { $detectedGeneration = "AMD (unknown generation)" Write-WULog -Message "WARNING: Could not determine AMD CPU generation from name: $cpuName" -Level Warning -LogPath $LogPath } } elseif ($cpu.Manufacturer -like "*Qualcomm*") { Write-WULog -Message "ARM processor detected" -LogPath $LogPath $detectedGeneration = "ARM Processor" # ARM processors - if Windows is running, assume compatible } else { Write-WULog -Message "Unknown CPU manufacturer: $($cpu.Manufacturer)" -Level Warning -LogPath $LogPath $detectedGeneration = "Unknown Manufacturer" } # Final decision if ($issues.Count -eq 0 -and $cpuSupported) { $result.Passed = $true Write-WULog -Message "CPU compatibility check PASSED: $($cpu.Name) ($detectedGeneration)" -LogPath $LogPath } else { if ($issues.Count -gt 0) { $result.Issue = $issues -join "; " } else { $result.Issue = $blockReason } Write-WULog -Message "CPU compatibility check FAILED: $($result.Issue)" -LogPath $LogPath } $result.Details["DetectedGeneration"] = $detectedGeneration $result.Details["SupportStatus"] = if ($cpuSupported) { "Supported" } else { "Not Supported" } $result.Details["BlockReason"] = $blockReason } catch { $result.Issue = "Error checking CPU compatibility: $($_.Exception.Message)" Write-WULog -Message $result.Issue -Level Error -LogPath $LogPath } return $result } function Test-WUMemoryRequirement { <# .SYNOPSIS Tests memory requirement (4GB minimum). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = 0 Issue = "" Details = @{} } try { # Try to get physically installed memory first $physicalMemoryKB = 0 try { Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class MemoryInfo { [DllImport("kernel32.dll")] public static extern bool GetPhysicallyInstalledSystemMemory(out long totalMemoryInKilobytes); } "@ $totalMemoryKB = 0 if ([MemoryInfo]::GetPhysicallyInstalledSystemMemory([ref]$totalMemoryKB)) { $physicalMemoryKB = $totalMemoryKB } } catch { # Fallback to WMI $totalMemory = Get-CimInstance -ClassName Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum $physicalMemoryKB = $totalMemory.Sum / 1KB } $memoryGB = [math]::Round($physicalMemoryKB / 1024 / 1024, 1) $result.Value = $memoryGB $result.Details["MemoryGB"] = $memoryGB $result.Details["MemoryKB"] = $physicalMemoryKB if ($memoryGB -ge 4) { $result.Passed = $true Write-WULog -Message "Memory check passed: $memoryGB GB" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires at least 4 GB of RAM (found: $memoryGB GB)" Write-WULog -Message "Memory check failed: $memoryGB GB" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine memory capacity" Write-WULog -Message "Error checking memory: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUStorageRequirement { <# .SYNOPSIS Tests storage requirement (64GB minimum). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = 0 Issue = "" Details = @{} } try { $systemDrive = $env:SystemDrive $drive = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $systemDrive } $totalSizeGB = [math]::Round($drive.Size / 1GB, 1) $result.Value = $totalSizeGB $result.Details["SystemDrive"] = $systemDrive $result.Details["TotalSizeGB"] = $totalSizeGB $result.Details["FreeSpaceGB"] = [math]::Round($drive.FreeSpace / 1GB, 1) if ($totalSizeGB -ge 64) { $result.Passed = $true Write-WULog -Message "Storage check passed: $totalSizeGB GB" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires at least 64 GB of storage (found: $totalSizeGB GB)" Write-WULog -Message "Storage check failed: $totalSizeGB GB" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine storage capacity" Write-WULog -Message "Error checking storage: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUTPMRequirement { <# .SYNOPSIS Tests TPM 2.0 requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Check TPM using WMI $tpm = Get-CimInstance -Namespace "root\cimv2\security\microsofttpm" -ClassName Win32_Tpm -ErrorAction SilentlyContinue if ($tpm) { $tpmVersion = $tpm.SpecVersion $tpmEnabled = $tpm.IsEnabled_InitialValue $tpmActivated = $tpm.IsActivated_InitialValue $result.Details["TPMPresent"] = $true $result.Details["TPMVersion"] = $tpmVersion $result.Details["TPMEnabled"] = $tpmEnabled $result.Details["TPMActivated"] = $tpmActivated if ($tpmVersion -like "2.0*") { if ($tpmEnabled -and $tpmActivated) { $result.Passed = $true $result.Value = $tpmVersion Write-WULog -Message "TPM check passed: Version $tpmVersion (enabled and activated)" -LogPath $LogPath } else { $result.Issue = "TPM 2.0 found but not enabled/activated (check BIOS settings)" $result.Value = "$tpmVersion (not ready)" Write-WULog -Message "TPM check failed: TPM 2.0 present but not ready" -LogPath $LogPath } } else { $result.Issue = "Windows 11 requires TPM 2.0 (found: $tpmVersion)" $result.Value = $tpmVersion Write-WULog -Message "TPM check failed: Version $tpmVersion" -LogPath $LogPath } } else { # Try alternative method $tpmStatus = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\TPM" -Name "Start" -ErrorAction SilentlyContinue if ($tpmStatus -and $tpmStatus.Start -eq 3) { $result.Issue = "TPM service is disabled" $result.Details["TPMPresent"] = $false } else { $result.Issue = "No TPM found (Windows 11 requires TPM 2.0)" $result.Details["TPMPresent"] = $false } Write-WULog -Message "TPM check failed: No TPM detected" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine TPM status" Write-WULog -Message "Error checking TPM: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUSecureBootRequirement { <# .SYNOPSIS Tests Secure Boot requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" CanBeEnabled = $false Details = @{} } try { $secureBootEnabled = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -Name "UEFISecureBootEnabled" -ErrorAction SilentlyContinue if ($secureBootEnabled) { $enabled = $secureBootEnabled.UEFISecureBootEnabled $result.Details["SecureBootEnabled"] = $enabled if ($enabled -eq 1) { $result.Passed = $true $result.Value = "Enabled" Write-WULog -Message "Secure Boot check passed: Enabled" -LogPath $LogPath } else { $result.Value = "Disabled" $result.CanBeEnabled = $true # If registry key exists, UEFI supports it $result.Issue = "Secure Boot is disabled (can be enabled in UEFI settings)" Write-WULog -Message "Secure Boot check warning: Disabled but can be enabled" -LogPath $LogPath } } else { $result.Issue = "Secure Boot not supported (UEFI firmware required)" $result.Value = "Not supported" Write-WULog -Message "Secure Boot check failed: Not supported" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine Secure Boot status" Write-WULog -Message "Error checking Secure Boot: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUDiskPartitioning { <# .SYNOPSIS Tests GPT disk partitioning requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Get system disk information $systemDrive = $env:SystemDrive $disk = Get-Partition | Where-Object { $_.DriveLetter -eq $systemDrive.TrimEnd(':') } | Get-Disk if ($disk) { $partitionStyle = $disk.PartitionStyle $result.Value = $partitionStyle $result.Details["PartitionStyle"] = $partitionStyle $result.Details["DiskNumber"] = $disk.Number if ($partitionStyle -eq "GPT") { $result.Passed = $true Write-WULog -Message "Disk partitioning check passed: GPT" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires GPT disk partitioning (found: $partitionStyle)" Write-WULog -Message "Disk partitioning check failed: $partitionStyle" -LogPath $LogPath } } else { $result.Issue = "Unable to determine disk partitioning scheme" Write-WULog -Message "Disk partitioning check failed: Cannot determine scheme" -LogPath $LogPath } } catch { $result.Issue = "Unable to check disk partitioning" Write-WULog -Message "Error checking disk partitioning: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUDirectXRequirement { <# .SYNOPSIS Tests DirectX 12 requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" IsWarning = $false Details = @{} } try { # Check DirectX via registry first (faster) $dxVersion = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\DirectX" -Name "Version" -ErrorAction SilentlyContinue if ($dxVersion) { $result.Details["DirectXVersion"] = $dxVersion.Version } # Check graphics capabilities $graphics = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.PNPDeviceID -notlike "*VEN_1414*" } | Select-Object -First 1 if ($graphics) { $result.Details["GraphicsCard"] = $graphics.Name $result.Details["DriverVersion"] = $graphics.DriverVersion $result.Details["DriverDate"] = $graphics.DriverDate # Basic check - if it's a modern graphics card, it likely supports DX12 $modernGPU = $graphics.Name -match "(RTX|GTX 1[0-9]|GTX 9[0-9]|RX [4-7][0-9]|Radeon.*[4-7][0-9]|Intel.*Iris|Intel.*UHD|Intel.*Xe)" if ($modernGPU) { $result.Passed = $true $result.Value = "Supported" Write-WULog -Message "DirectX 12 check passed: Modern GPU detected" -LogPath $LogPath } else { $result.IsWarning = $true $result.Issue = "Graphics card may not support DirectX 12 (manual verification recommended)" $result.Value = "Unknown" Write-WULog -Message "DirectX 12 check warning: Unable to confirm support" -LogPath $LogPath } } else { $result.IsWarning = $true $result.Issue = "No graphics card detected or unable to determine DirectX 12 support" Write-WULog -Message "DirectX 12 check warning: No graphics card detected" -LogPath $LogPath } } catch { $result.IsWarning = $true $result.Issue = "Unable to determine DirectX 12 support" Write-WULog -Message "Error checking DirectX 12: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUInternetConnectivity { <# .SYNOPSIS Tests internet connectivity for Windows Updates. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Test connectivity to Microsoft Update servers $testUrls = @( "https://www.microsoft.com", "https://update.microsoft.com", "https://windowsupdate.microsoft.com" ) $connectedCount = 0 foreach ($url in $testUrls) { try { $response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { $connectedCount++ } } catch { # Connection failed to this URL } } $result.Details["TestedUrls"] = $testUrls.Count $result.Details["SuccessfulConnections"] = $connectedCount if ($connectedCount -gt 0) { $result.Passed = $true $result.Value = "Connected" Write-WULog -Message "Internet connectivity check passed: $connectedCount/$($testUrls.Count) connections successful" -LogPath $LogPath } else { $result.Issue = "No internet connectivity detected (required for Windows Updates)" $result.Value = "Disconnected" Write-WULog -Message "Internet connectivity check failed: No connections successful" -LogPath $LogPath } } catch { $result.Issue = "Unable to test internet connectivity" Write-WULog -Message "Error checking internet connectivity: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result }function Test-WUWindows11Compatibility { <# .SYNOPSIS Tests Windows 11 upgrade compatibility requirements. .DESCRIPTION Comprehensive Windows 11 compatibility assessment checking all major requirements including CPU, TPM, Secure Boot, UEFI, memory, storage, and more. Also checks for existing Microsoft compatibility holds via registry. .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $compatibility = Test-WUWindows11Compatibility -LogPath "C:\Logs\wu.log" .NOTES This is a private function used internally by the WindowsUpdateTools module. Returns detailed Windows 11 compatibility assessment. #> [CmdletBinding()] param( [string]$LogPath ) Write-WULog -Message "Starting Windows 11 compatibility assessment" -LogPath $LogPath # Initialize results object $results = [PSCustomObject]@{ Compatible = $true OverallAssessment = "Compatible" Checks = @{} FailedChecks = @() WarningChecks = @() CompatibilityHolds = @() SystemInfo = @{} Issues = @() ErrorMessage = $null } try { # Get current OS info for context $osInfo = Get-CimInstance -ClassName Win32_OperatingSystem $currentBuild = $osInfo.BuildNumber Write-WULog -Message "Current OS: $($osInfo.Caption) Build $currentBuild" -LogPath $LogPath # Check for existing Microsoft compatibility holds first Write-WULog -Message "Checking for existing Microsoft compatibility holds..." -LogPath $LogPath $compatibilityHolds = Test-WUCompatibilityHolds -LogPath $LogPath if ($compatibilityHolds.Count -gt 0) { $results.CompatibilityHolds = $compatibilityHolds $results.Compatible = $false $results.OverallAssessment = "Blocked by Microsoft" foreach ($hold in $compatibilityHolds) { $results.Issues += "Microsoft compatibility hold: $hold" } } # 1. Architecture Check (64-bit requirement) Write-WULog -Message "Checking system architecture..." -LogPath $LogPath $archCheck = Test-WUArchitecture -LogPath $LogPath $results.Checks["Architecture"] = $archCheck if (-not $archCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Architecture" $results.Issues += $archCheck.Issue } # 2. UEFI/Boot Mode Check Write-WULog -Message "Checking boot mode (UEFI requirement)..." -LogPath $LogPath $bootCheck = Test-WUBootMode -LogPath $LogPath $results.Checks["BootMode"] = $bootCheck if (-not $bootCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "BootMode" $results.Issues += $bootCheck.Issue } # 3. CPU Compatibility Check Write-WULog -Message "Checking CPU compatibility..." -LogPath $LogPath $cpuCheck = Test-WUCPUCompatibility -LogPath $LogPath $results.Checks["CPU"] = $cpuCheck if (-not $cpuCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "CPU" $results.Issues += $cpuCheck.Issue } # 4. Memory Check (4GB minimum) Write-WULog -Message "Checking memory requirements..." -LogPath $LogPath $memoryCheck = Test-WUMemoryRequirement -LogPath $LogPath $results.Checks["Memory"] = $memoryCheck if (-not $memoryCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Memory" $results.Issues += $memoryCheck.Issue } # 5. Storage Check (64GB minimum) Write-WULog -Message "Checking storage requirements..." -LogPath $LogPath $storageCheck = Test-WUStorageRequirement -LogPath $LogPath $results.Checks["Storage"] = $storageCheck if (-not $storageCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "Storage" $results.Issues += $storageCheck.Issue } # 6. TPM Check (2.0 requirement) Write-WULog -Message "Checking TPM requirements..." -LogPath $LogPath $tpmCheck = Test-WUTPMRequirement -LogPath $LogPath $results.Checks["TPM"] = $tpmCheck if (-not $tpmCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "TPM" $results.Issues += $tpmCheck.Issue } # 7. Secure Boot Check Write-WULog -Message "Checking Secure Boot requirements..." -LogPath $LogPath $secureBootCheck = Test-WUSecureBootRequirement -LogPath $LogPath $results.Checks["SecureBoot"] = $secureBootCheck if (-not $secureBootCheck.Passed) { # Secure Boot can be enabled, so this might be a warning rather than failure if ($secureBootCheck.CanBeEnabled) { $results.WarningChecks += "SecureBoot" $results.Issues += "Warning: " + $secureBootCheck.Issue } else { $results.Compatible = $false $results.FailedChecks += "SecureBoot" $results.Issues += $secureBootCheck.Issue } } # 8. GPT Disk Check Write-WULog -Message "Checking disk partitioning (GPT requirement)..." -LogPath $LogPath $diskCheck = Test-WUDiskPartitioning -LogPath $LogPath $results.Checks["DiskPartitioning"] = $diskCheck if (-not $diskCheck.Passed) { $results.Compatible = $false $results.FailedChecks += "DiskPartitioning" $results.Issues += $diskCheck.Issue } # 9. DirectX 12 Check Write-WULog -Message "Checking DirectX 12 requirements..." -LogPath $LogPath $dxCheck = Test-WUDirectXRequirement -LogPath $LogPath $results.Checks["DirectX12"] = $dxCheck if (-not $dxCheck.Passed) { if ($dxCheck.IsWarning) { $results.WarningChecks += "DirectX12" $results.Issues += "Warning: " + $dxCheck.Issue } else { $results.Compatible = $false $results.FailedChecks += "DirectX12" $results.Issues += $dxCheck.Issue } } # 10. Internet Connectivity Check (for updates) Write-WULog -Message "Checking internet connectivity..." -LogPath $LogPath $internetCheck = Test-WUInternetConnectivity -LogPath $LogPath $results.Checks["InternetConnectivity"] = $internetCheck if (-not $internetCheck.Passed) { $results.WarningChecks += "InternetConnectivity" $results.Issues += "Warning: " + $internetCheck.Issue } # Determine overall assessment if ($results.CompatibilityHolds.Count -gt 0) { $results.OverallAssessment = "Blocked by Microsoft compatibility hold" } elseif ($results.FailedChecks.Count -gt 0) { $results.OverallAssessment = "Not compatible - $($results.FailedChecks.Count) requirement(s) failed" $results.Compatible = $false } elseif ($results.WarningChecks.Count -gt 0) { $results.OverallAssessment = "Compatible with warnings - $($results.WarningChecks.Count) item(s) need attention" } else { $results.OverallAssessment = "Fully compatible" } # Log summary Write-WULog -Message "Windows 11 compatibility assessment completed:" -LogPath $LogPath Write-WULog -Message " Overall: $($results.OverallAssessment)" -LogPath $LogPath Write-WULog -Message " Failed checks: $($results.FailedChecks.Count)" -LogPath $LogPath Write-WULog -Message " Warning checks: $($results.WarningChecks.Count)" -LogPath $LogPath Write-WULog -Message " Compatibility holds: $($results.CompatibilityHolds.Count)" -LogPath $LogPath if ($results.FailedChecks.Count -gt 0) { Write-WULog -Message "Failed requirements: $($results.FailedChecks -join ', ')" -Level Warning -LogPath $LogPath } } catch { $results.ErrorMessage = $_.Exception.Message Write-WULog -Message "Error during Windows 11 compatibility assessment: $($_.Exception.Message)" -Level Error -LogPath $LogPath } return $results } function Test-WUArchitecture { <# .SYNOPSIS Tests CPU architecture requirements (64-bit). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { $cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object -First 1 $os = Get-CimInstance -ClassName Win32_OperatingSystem $result.Value = $cpu.Architecture $result.Details["CPUArchitecture"] = $cpu.Architecture $result.Details["OSArchitecture"] = $os.OSArchitecture # Check for 64-bit capability if ($cpu.Architecture -eq 9) { # 9 = x64 $result.Passed = $true Write-WULog -Message "Architecture check passed: x64" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires 64-bit (x64) processor architecture" Write-WULog -Message "Architecture check failed: $($cpu.Architecture)" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine system architecture" Write-WULog -Message "Error checking architecture: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUBootMode { <# .SYNOPSIS Tests UEFI boot mode requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Check firmware type $firmwareType = $env:firmware_type $result.Value = $firmwareType if ($firmwareType -eq "UEFI") { $result.Passed = $true Write-WULog -Message "Boot mode check passed: UEFI" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires UEFI firmware (Legacy BIOS not supported)" Write-WULog -Message "Boot mode check failed: $firmwareType" -LogPath $LogPath } $result.Details["FirmwareType"] = $firmwareType } catch { $result.Issue = "Unable to determine boot mode" Write-WULog -Message "Error checking boot mode: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUMemoryRequirement { <# .SYNOPSIS Tests memory requirement (4GB minimum). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = 0 Issue = "" Details = @{} } try { # Try to get physically installed memory first $physicalMemoryKB = 0 try { Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class MemoryInfo { [DllImport("kernel32.dll")] public static extern bool GetPhysicallyInstalledSystemMemory(out long totalMemoryInKilobytes); } "@ $totalMemoryKB = 0 if ([MemoryInfo]::GetPhysicallyInstalledSystemMemory([ref]$totalMemoryKB)) { $physicalMemoryKB = $totalMemoryKB } } catch { # Fallback to WMI $totalMemory = Get-CimInstance -ClassName Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum $physicalMemoryKB = $totalMemory.Sum / 1KB } $memoryGB = [math]::Round($physicalMemoryKB / 1024 / 1024, 1) $result.Value = $memoryGB $result.Details["MemoryGB"] = $memoryGB $result.Details["MemoryKB"] = $physicalMemoryKB if ($memoryGB -ge 4) { $result.Passed = $true Write-WULog -Message "Memory check passed: $memoryGB GB" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires at least 4 GB of RAM (found: $memoryGB GB)" Write-WULog -Message "Memory check failed: $memoryGB GB" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine memory capacity" Write-WULog -Message "Error checking memory: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUStorageRequirement { <# .SYNOPSIS Tests storage requirement (64GB minimum). #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = 0 Issue = "" Details = @{} } try { $systemDrive = $env:SystemDrive $drive = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $systemDrive } $totalSizeGB = [math]::Round($drive.Size / 1GB, 1) $result.Value = $totalSizeGB $result.Details["SystemDrive"] = $systemDrive $result.Details["TotalSizeGB"] = $totalSizeGB $result.Details["FreeSpaceGB"] = [math]::Round($drive.FreeSpace / 1GB, 1) if ($totalSizeGB -ge 64) { $result.Passed = $true Write-WULog -Message "Storage check passed: $totalSizeGB GB" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires at least 64 GB of storage (found: $totalSizeGB GB)" Write-WULog -Message "Storage check failed: $totalSizeGB GB" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine storage capacity" Write-WULog -Message "Error checking storage: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUTPMRequirement { <# .SYNOPSIS Tests TPM 2.0 requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Check TPM using WMI $tpm = Get-CimInstance -Namespace "root\cimv2\security\microsofttpm" -ClassName Win32_Tpm -ErrorAction SilentlyContinue if ($tpm) { $tpmVersion = $tpm.SpecVersion $tpmEnabled = $tpm.IsEnabled_InitialValue $tpmActivated = $tpm.IsActivated_InitialValue $result.Details["TPMPresent"] = $true $result.Details["TPMVersion"] = $tpmVersion $result.Details["TPMEnabled"] = $tpmEnabled $result.Details["TPMActivated"] = $tpmActivated if ($tpmVersion -like "2.0*") { if ($tpmEnabled -and $tpmActivated) { $result.Passed = $true $result.Value = $tpmVersion Write-WULog -Message "TPM check passed: Version $tpmVersion (enabled and activated)" -LogPath $LogPath } else { $result.Issue = "TPM 2.0 found but not enabled/activated (check BIOS settings)" $result.Value = "$tpmVersion (not ready)" Write-WULog -Message "TPM check failed: TPM 2.0 present but not ready" -LogPath $LogPath } } else { $result.Issue = "Windows 11 requires TPM 2.0 (found: $tpmVersion)" $result.Value = $tpmVersion Write-WULog -Message "TPM check failed: Version $tpmVersion" -LogPath $LogPath } } else { # Try alternative method $tpmStatus = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\TPM" -Name "Start" -ErrorAction SilentlyContinue if ($tpmStatus -and $tpmStatus.Start -eq 3) { $result.Issue = "TPM service is disabled" $result.Details["TPMPresent"] = $false } else { $result.Issue = "No TPM found (Windows 11 requires TPM 2.0)" $result.Details["TPMPresent"] = $false } Write-WULog -Message "TPM check failed: No TPM detected" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine TPM status" Write-WULog -Message "Error checking TPM: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUSecureBootRequirement { <# .SYNOPSIS Tests Secure Boot requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" CanBeEnabled = $false Details = @{} } try { $secureBootEnabled = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -Name "UEFISecureBootEnabled" -ErrorAction SilentlyContinue if ($secureBootEnabled) { $enabled = $secureBootEnabled.UEFISecureBootEnabled $result.Details["SecureBootEnabled"] = $enabled if ($enabled -eq 1) { $result.Passed = $true $result.Value = "Enabled" Write-WULog -Message "Secure Boot check passed: Enabled" -LogPath $LogPath } else { $result.Value = "Disabled" $result.CanBeEnabled = $true # If registry key exists, UEFI supports it $result.Issue = "Secure Boot is disabled (can be enabled in UEFI settings)" Write-WULog -Message "Secure Boot check warning: Disabled but can be enabled" -LogPath $LogPath } } else { $result.Issue = "Secure Boot not supported (UEFI firmware required)" $result.Value = "Not supported" Write-WULog -Message "Secure Boot check failed: Not supported" -LogPath $LogPath } } catch { $result.Issue = "Unable to determine Secure Boot status" Write-WULog -Message "Error checking Secure Boot: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUDiskPartitioning { <# .SYNOPSIS Tests GPT disk partitioning requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Get system disk information $systemDrive = $env:SystemDrive $disk = Get-Partition | Where-Object { $_.DriveLetter -eq $systemDrive.TrimEnd(':') } | Get-Disk if ($disk) { $partitionStyle = $disk.PartitionStyle $result.Value = $partitionStyle $result.Details["PartitionStyle"] = $partitionStyle $result.Details["DiskNumber"] = $disk.Number if ($partitionStyle -eq "GPT") { $result.Passed = $true Write-WULog -Message "Disk partitioning check passed: GPT" -LogPath $LogPath } else { $result.Issue = "Windows 11 requires GPT disk partitioning (found: $partitionStyle)" Write-WULog -Message "Disk partitioning check failed: $partitionStyle" -LogPath $LogPath } } else { $result.Issue = "Unable to determine disk partitioning scheme" Write-WULog -Message "Disk partitioning check failed: Cannot determine scheme" -LogPath $LogPath } } catch { $result.Issue = "Unable to check disk partitioning" Write-WULog -Message "Error checking disk partitioning: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUDirectXRequirement { <# .SYNOPSIS Tests DirectX 12 requirement. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" IsWarning = $false Details = @{} } try { # Check DirectX via registry first (faster) $dxVersion = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\DirectX" -Name "Version" -ErrorAction SilentlyContinue if ($dxVersion) { $result.Details["DirectXVersion"] = $dxVersion.Version } # Check graphics capabilities $graphics = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.PNPDeviceID -notlike "*VEN_1414*" } | Select-Object -First 1 if ($graphics) { $result.Details["GraphicsCard"] = $graphics.Name $result.Details["DriverVersion"] = $graphics.DriverVersion $result.Details["DriverDate"] = $graphics.DriverDate # Basic check - if it's a modern graphics card, it likely supports DX12 $modernGPU = $graphics.Name -match "(RTX|GTX 1[0-9]|GTX 9[0-9]|RX [4-7][0-9]|Radeon.*[4-7][0-9]|Intel.*Iris|Intel.*UHD|Intel.*Xe)" if ($modernGPU) { $result.Passed = $true $result.Value = "Supported" Write-WULog -Message "DirectX 12 check passed: Modern GPU detected" -LogPath $LogPath } else { $result.IsWarning = $true $result.Issue = "Graphics card may not support DirectX 12 (manual verification recommended)" $result.Value = "Unknown" Write-WULog -Message "DirectX 12 check warning: Unable to confirm support" -LogPath $LogPath } } else { $result.IsWarning = $true $result.Issue = "No graphics card detected or unable to determine DirectX 12 support" Write-WULog -Message "DirectX 12 check warning: No graphics card detected" -LogPath $LogPath } } catch { $result.IsWarning = $true $result.Issue = "Unable to determine DirectX 12 support" Write-WULog -Message "Error checking DirectX 12: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } function Test-WUInternetConnectivity { <# .SYNOPSIS Tests internet connectivity for Windows Updates. #> param([string]$LogPath) $result = [PSCustomObject]@{ Passed = $false Value = "" Issue = "" Details = @{} } try { # Test connectivity to Microsoft Update servers $testUrls = @( "https://www.microsoft.com", "https://update.microsoft.com", "https://windowsupdate.microsoft.com" ) $connectedCount = 0 foreach ($url in $testUrls) { try { $response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop if ($response.StatusCode -eq 200) { $connectedCount++ } } catch { # Connection failed to this URL } } $result.Details["TestedUrls"] = $testUrls.Count $result.Details["SuccessfulConnections"] = $connectedCount if ($connectedCount -gt 0) { $result.Passed = $true $result.Value = "Connected" Write-WULog -Message "Internet connectivity check passed: $connectedCount/$($testUrls.Count) connections successful" -LogPath $LogPath } else { $result.Issue = "No internet connectivity detected (required for Windows Updates)" $result.Value = "Disconnected" Write-WULog -Message "Internet connectivity check failed: No connections successful" -LogPath $LogPath } } catch { $result.Issue = "Unable to test internet connectivity" Write-WULog -Message "Error checking internet connectivity: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $result } |