Private/Get-WUConfiguration.ps1
|
function Get-WUConfiguration { <# .SYNOPSIS Analyzes Windows Update configuration including WSUS settings and policies. .DESCRIPTION Comprehensive analysis of Windows Update configuration including WSUS server settings, Group Policy configurations, Windows Update for Business settings, and compatibility checks for Windows 11 24H2. .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $config = Get-WUConfiguration -LogPath "C:\Logs\wu.log" .NOTES This is a private function used internally by the WindowsUpdateTools module. Returns detailed Windows Update configuration analysis. #> [CmdletBinding()] param( [string]$LogPath ) Write-WULog -Message "Analyzing Windows Update configuration" -LogPath $LogPath # Initialize results object $results = [PSCustomObject]@{ WSUSConfigured = $false WSUSServer = $null WSUSStatusServer = $null UpdateSource = "Windows Update" AutoUpdateEnabled = $true TargetGroup = $null UpdatePolicy = "Default" PolicySource = "None" # None, LocalGPO, DomainGPO, MDM/Intune WindowsUpdateForBusiness = $false IntuneUpdateRingEnrolled = $false # Specifically tracks if enrolled in Intune Update Rings Windows11_24H2_Compatible = $true DeferralSettings = @{} Issues = @() Configuration = @{} RegistrySettings = @{} ErrorMessage = $null } try { # Detect policy source first $policySource = "None" # Check if device is MDM enrolled (Intune) $mdmEnrollmentPath = "HKLM:\SOFTWARE\Microsoft\Enrollments" if (Test-Path $mdmEnrollmentPath) { $enrollments = Get-ChildItem -Path $mdmEnrollmentPath -ErrorAction SilentlyContinue foreach ($enrollment in $enrollments) { $enrollmentInfo = Get-ItemProperty -Path $enrollment.PSPath -ErrorAction SilentlyContinue if ($enrollmentInfo.ProviderID -eq "MS DM Server" -or $enrollmentInfo.EnrollmentType -eq 6) { $policySource = "MDM/Intune" Write-WULog -Message "Device is MDM enrolled (Intune managed)" -LogPath $LogPath break } } } # Check for domain membership $computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction SilentlyContinue if ($computerSystem.PartOfDomain -and $policySource -eq "None") { $policySource = "DomainGPO" Write-WULog -Message "Device is domain-joined: $($computerSystem.Domain)" -LogPath $LogPath } # Check if policies exist but no MDM/Domain (local GPO) if ($policySource -eq "None" -and (Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU")) { $policySource = "LocalGPO" Write-WULog -Message "Windows Update policies found - likely Local Group Policy" -LogPath $LogPath } $results.PolicySource = $policySource Write-WULog -Message "Checking WSUS configuration..." -LogPath $LogPath # Check for WSUS registry settings $wsusRegPaths = @{ "WindowsUpdate" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" "AutoUpdate" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" } foreach ($regKey in $wsusRegPaths.GetEnumerator()) { $regPath = $regKey.Value $keyName = $regKey.Key if (Test-Path $regPath) { Write-WULog -Message "Found $keyName registry configuration at: $regPath" -LogPath $LogPath try { $regProperties = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue $results.RegistrySettings[$keyName] = @{} foreach ($property in $regProperties.PSObject.Properties) { if ($property.Name -notlike "PS*") { $results.RegistrySettings[$keyName][$property.Name] = $property.Value } } # Check specific WSUS settings if ($keyName -eq "WindowsUpdate") { if ($regProperties.WUServer) { $results.WSUSConfigured = $true $results.WSUSServer = $regProperties.WUServer $results.UpdateSource = "WSUS" Write-WULog -Message "WSUS Server configured: $($regProperties.WUServer)" -LogPath $LogPath } if ($regProperties.WUStatusServer) { $results.WSUSStatusServer = $regProperties.WUStatusServer Write-WULog -Message "WSUS Status Server: $($regProperties.WUStatusServer)" -LogPath $LogPath } if ($regProperties.TargetGroup) { $results.TargetGroup = $regProperties.TargetGroup Write-WULog -Message "WSUS Target Group: $($regProperties.TargetGroup)" -LogPath $LogPath } } if ($keyName -eq "AutoUpdate") { # Log the actual registry values for transparency if ($null -ne $regProperties.NoAutoUpdate) { Write-WULog -Message " Registry: NoAutoUpdate = $($regProperties.NoAutoUpdate)" -LogPath $LogPath } if ($null -ne $regProperties.AUOptions) { Write-WULog -Message " Registry: AUOptions = $($regProperties.AUOptions)" -LogPath $LogPath } if ($regProperties.NoAutoUpdate -eq 1) { $results.AutoUpdateEnabled = $false $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Critical" ` -Description "Windows Update is DISABLED: NoAutoUpdate=1 set in registry" ` -Details @{ RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' NoAutoUpdate = 1 PolicySource = $results.PolicySource } ` -Remediation "Remove NoAutoUpdate registry key or configure Intune Update Ring to manage updates" Write-WULog -Message "Automatic updates DISABLED: NoAutoUpdate=1 in registry" -Level Warning -LogPath $LogPath Write-WULog -Message " Policy Source: HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Level Warning -LogPath $LogPath } if ($regProperties.AUOptions) { $auOption = switch ($regProperties.AUOptions) { 1 { "Disabled - Never check for updates" } 2 { "Notify before download" } 3 { "Auto download, notify for install" } 4 { "Auto download and scheduled install" } 5 { "Allow local admin to configure" } default { "Unknown ($($regProperties.AUOptions))" } } $results.UpdatePolicy = $auOption Write-WULog -Message "Auto Update Policy: AUOptions=$($regProperties.AUOptions) ($auOption)" -LogPath $LogPath if ($regProperties.AUOptions -eq 1) { $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Critical" ` -Description "AUOptions=1: Windows Update checking is completely disabled" ` -Details @{ AUOptions = 1; PolicySource = $results.PolicySource } ` -Remediation "Configure AUOptions to 3 or 4 for automatic updates, or use Intune Update Ring" } } } } catch { Write-WULog -Message "Error reading $keyName registry settings: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } # Check Windows Update for Business / Intune Update Ring enrollment Write-WULog -Message "Checking Windows Update for Business / Intune Update Ring configuration..." -LogPath $LogPath # Check MDM PolicyManager for WUfB enrollment status (Intune Update Rings) $mdmUpdatePath = "HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device\Update" if (Test-Path $mdmUpdatePath) { try { $mdmUpdateProps = Get-ItemProperty -Path $mdmUpdatePath -ErrorAction SilentlyContinue # Check enrollment status for each update type $enrollmentTypes = @{ 'QualityUpdateEnrolled' = 'Quality Updates (Security/Cumulative)' 'FeatureUpdateEnrolled' = 'Feature Updates (Version Upgrades)' 'DriverUpdateEnrolled' = 'Driver Updates' } $anyEnrolled = $false foreach ($enrollment in $enrollmentTypes.GetEnumerator()) { $propName = $enrollment.Key $description = $enrollment.Value if ($null -ne $mdmUpdateProps.$propName) { $enrolled = $mdmUpdateProps.$propName -eq 1 $providerProp = "${propName}_WinningProvider" $provider = if ($mdmUpdateProps.$providerProp) { $mdmUpdateProps.$providerProp } else { "Unknown" } # Known Intune provider GUID $providerName = if ($provider -eq "B04F44A4-B696-4B56-934A-C11667E944E4") { "Intune" } else { $provider } $status = if ($enrolled) { "ENROLLED" } else { "NOT ENROLLED" } Write-WULog -Message " MDM Update Ring: $description = $status (Provider: $providerName)" -LogPath $LogPath $results.DeferralSettings["MDM_$propName"] = $mdmUpdateProps.$propName $results.DeferralSettings["MDM_${propName}_Provider"] = $providerName if ($enrolled) { $anyEnrolled = $true } } } # If device is MDM enrolled but not enrolled in any Update Rings, flag it if ($results.PolicySource -eq "MDM/Intune" -and -not $anyEnrolled) { $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Critical" ` -Description "Device is Intune-enrolled but NOT enrolled in any Windows Update for Business Update Rings" ` -Details @{ QualityUpdateEnrolled = $false FeatureUpdateEnrolled = $false DriverUpdateEnrolled = $false } ` -Remediation "Assign device to an Intune Update Ring in Endpoint Manager: Devices > Windows > Update rings" Write-WULog -Message "Device is MDM-managed but has no Update Ring enrollment - updates may not be managed" -Level Warning -LogPath $LogPath } if ($anyEnrolled) { $results.WindowsUpdateForBusiness = $true $results.IntuneUpdateRingEnrolled = $true Write-WULog -Message "Device is enrolled in Intune Update Rings for Windows Update management" -LogPath $LogPath } # Check additional MDM update settings if ($null -ne $mdmUpdateProps.AllowRebootlessUpdates) { Write-WULog -Message " MDM Setting: AllowRebootlessUpdates = $($mdmUpdateProps.AllowRebootlessUpdates)" -LogPath $LogPath } } catch { Write-WULog -Message "Error reading MDM Update settings: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Check traditional WUfB registry paths for deferral settings $wufbRegPaths = @( "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" ) foreach ($wufbPath in $wufbRegPaths) { if (Test-Path $wufbPath) { try { $wufbProperties = Get-ItemProperty -Path $wufbPath -ErrorAction SilentlyContinue # Check for Windows Update for Business deferral indicators $wufbIndicators = @('DeferFeatureUpdates', 'DeferQualityUpdates', 'BranchReadinessLevel', 'ManagePreviewBuilds', 'DeferFeatureUpdatesPeriodInDays', 'DeferQualityUpdatesPeriodInDays') foreach ($indicator in $wufbIndicators) { if ($null -ne $wufbProperties.$indicator) { $results.WindowsUpdateForBusiness = $true $results.DeferralSettings[$indicator] = $wufbProperties.$indicator Write-WULog -Message " WUfB GPO Setting: $indicator = $($wufbProperties.$indicator)" -LogPath $LogPath } } } catch { Write-WULog -Message "Error reading WUfB settings from $wufbPath`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } # Check for Windows 11 24H2 compatibility issues Write-WULog -Message "Checking Windows 11 24H2 compatibility..." -LogPath $LogPath $osVersion = (Get-CimInstance Win32_OperatingSystem).Version if ($results.WSUSConfigured -and $osVersion -like "10.0.22*") { Write-WULog -Message "Windows 11 system with WSUS detected - checking 24H2 compatibility" -LogPath $LogPath # Check for the critical Windows 11 24H2 registry fix $featureManagementPath = "HKLM:\SYSTEM\CurrentControlSet\Control\FeatureManagement\Overrides\8\3000950414" if (Test-Path $featureManagementPath) { try { $featureProps = Get-ItemProperty -Path $featureManagementPath -ErrorAction SilentlyContinue if ($featureProps.EnabledState -eq 1) { Write-WULog -Message "Windows 11 24H2 feature management registry fix is applied" -LogPath $LogPath } else { $results.Windows11_24H2_Compatible = $false $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Warning" ` -Description "Windows 11 24H2 feature management registry fix not properly configured" ` -Remediation "Apply KB5037771 or later, or manually set EnabledState=1 in feature management registry" Write-WULog -Message "Windows 11 24H2 compatibility issue - EnabledState not set to 1" -Level Warning -LogPath $LogPath } } catch { $results.Windows11_24H2_Compatible = $false $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Warning" ` -Description "Could not verify Windows 11 24H2 feature management settings" ` -Details @{ Error = $_.Exception.Message } Write-WULog -Message "Error checking Windows 11 24H2 feature management: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } else { $results.Windows11_24H2_Compatible = $false $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Warning" ` -Description "Windows 11 24H2 feature management registry not found - may cause upgrade issues" ` -Remediation "Apply KB5037771 or later to enable 24H2 upgrade compatibility" Write-WULog -Message "Windows 11 24H2 feature management registry not found" -Level Warning -LogPath $LogPath } } # Check for additional configuration issues Write-WULog -Message "Checking for additional configuration issues..." -LogPath $LogPath # Check if Windows Update service is properly configured try { $wuServiceConfig = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv" -ErrorAction SilentlyContinue if ($wuServiceConfig) { if ($wuServiceConfig.Start -eq 4) { # 4 = Disabled $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Critical" ` -Description "Windows Update service (wuauserv) is disabled at the system level" ` -Remediation "Run: Set-Service wuauserv -StartupType Manual" Write-WULog -Message "Windows Update service is disabled at system level" -Level Warning -LogPath $LogPath } } } catch { Write-WULog -Message "Could not check Windows Update service configuration" -Level Warning -LogPath $LogPath } # Check for metered connection settings that might block updates try { $meteredPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\DefaultMediaCost" if (Test-Path $meteredPath) { $meteredProps = Get-ItemProperty -Path $meteredPath -ErrorAction SilentlyContinue if ($meteredProps -and $meteredProps.Default -gt 1) { $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Warning" ` -Description "Metered connection settings may prevent automatic updates" Write-WULog -Message "Metered connection settings detected" -Level Warning -LogPath $LogPath } } } catch { Write-WULog -Message "Could not check metered connection settings" -Level Warning -LogPath $LogPath } # Check for proxy settings that might affect Windows Update try { $proxyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings" if (Test-Path $proxyPath) { $proxyProps = Get-ItemProperty -Path $proxyPath -ErrorAction SilentlyContinue if ($proxyProps.ProxyEnable -eq 1) { Write-WULog -Message "System proxy configured: $($proxyProps.ProxyServer)" -LogPath $LogPath $results.Configuration["ProxyEnabled"] = $true $results.Configuration["ProxyServer"] = $proxyProps.ProxyServer # Check if Windows Update URLs are bypassed if ($proxyProps.ProxyOverride -and $proxyProps.ProxyOverride -like "*microsoft.com*") { Write-WULog -Message "Microsoft domains appear to be proxy-bypassed" -LogPath $LogPath } else { $results.Issues += New-WUHealthIssue -Type "Configuration" -Severity "Warning" ` -Description "Proxy configuration may interfere with Windows Update connectivity" ` -Details @{ ProxyServer = $proxyProps.ProxyServer } ` -Remediation "Add *.microsoft.com and *.windowsupdate.com to proxy bypass list" Write-WULog -Message "Proxy may interfere with Windows Update" -Level Warning -LogPath $LogPath } } } } catch { Write-WULog -Message "Could not check proxy configuration" -Level Warning -LogPath $LogPath } # Build configuration summary $results.Configuration["UpdateSource"] = $results.UpdateSource $results.Configuration["AutoUpdateEnabled"] = $results.AutoUpdateEnabled $results.Configuration["UpdatePolicy"] = $results.UpdatePolicy $results.Configuration["WSUSConfigured"] = $results.WSUSConfigured $results.Configuration["WindowsUpdateForBusiness"] = $results.WindowsUpdateForBusiness $results.Configuration["IntuneUpdateRingEnrolled"] = $results.IntuneUpdateRingEnrolled } catch { $results.ErrorMessage = $_.Exception.Message Write-WULog -Message "Critical error during configuration analysis: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Summary Write-WULog -Message "Windows Update configuration analysis completed:" -LogPath $LogPath Write-WULog -Message " Update Source: $($results.UpdateSource)" -LogPath $LogPath Write-WULog -Message " Policy Source: $($results.PolicySource)" -LogPath $LogPath Write-WULog -Message " WSUS Configured: $($results.WSUSConfigured)" -LogPath $LogPath Write-WULog -Message " Auto Update Enabled: $($results.AutoUpdateEnabled)" -LogPath $LogPath if (-not $results.AutoUpdateEnabled) { Write-WULog -Message " Update Policy: $($results.UpdatePolicy)" -Level Warning -LogPath $LogPath } Write-WULog -Message " WUfB Configured: $($results.WindowsUpdateForBusiness)" -LogPath $LogPath if ($results.PolicySource -eq "MDM/Intune") { $enrolledStatus = if ($results.IntuneUpdateRingEnrolled) { "Yes" } else { "NO - Device not receiving managed updates!" } Write-WULog -Message " Intune Update Ring Enrolled: $enrolledStatus" -LogPath $LogPath } Write-WULog -Message " Windows 11 24H2 Compatible: $($results.Windows11_24H2_Compatible)" -LogPath $LogPath Write-WULog -Message " Configuration Issues: $($results.Issues.Count)" -LogPath $LogPath if ($results.Issues.Count -gt 0) { Write-WULog -Message "Configuration issues found:" -LogPath $LogPath foreach ($issue in $results.Issues) { $severity = if ($issue.Severity -eq "Critical") { "Error" } else { "Warning" } Write-WULog -Message " - [$($issue.Severity)] $($issue.Description)" -Level $severity -LogPath $LogPath if ($issue.Remediation) { Write-WULog -Message " Remediation: $($issue.Remediation)" -LogPath $LogPath } } } return $results } |