dist/temp/WindowsUpdateTools/Private/Resolve-WUDynamicUpdatesIssues.ps1
|
function Resolve-WUDynamicUpdatesIssues { <# .SYNOPSIS Resolves Dynamic Updates configuration and download failures. .DESCRIPTION Fixes Dynamic Updates failures including: - 0x80070057: WU internal configuration property failures - 0x80004005: Download update failures - CopyFileBufferedSynchronousIo registry issues - Windows Update component corruption .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $result = Resolve-WUDynamicUpdatesIssues -LogPath "C:\Logs\wu.log" .NOTES This is a private function used internally by the WindowsUpdateTools module. Requires Administrator privileges for service and registry modification. Returns an object with Success, ActionsPerformed, and RebootRequired properties. #> [CmdletBinding()] param( [string]$LogPath ) # Initialize result object $result = [PSCustomObject]@{ Success = $false RebootRequired = $false ActionsPerformed = @() IssuesResolved = 0 ErrorMessage = $null ServicesReset = $false RegistryFixed = $false ComponentsCleared = $false } Write-WULog -Message "Starting Dynamic Updates issues remediation" -LogPath $LogPath try { # Step 1: Stop Windows Update services Write-WULog -Message "Step 1: Stopping Windows Update services..." -LogPath $LogPath $services = @('wuauserv', 'bits', 'cryptsvc', 'msiserver') $stoppedServices = @() foreach ($service in $services) { try { $serviceObj = Get-Service -Name $service -ErrorAction SilentlyContinue if ($serviceObj -and $serviceObj.Status -eq 'Running') { Stop-Service -Name $service -Force -ErrorAction Stop $stoppedServices += $service Write-WULog -Message "Stopped service: $service" -LogPath $LogPath } } catch { Write-WULog -Message "Failed to stop service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } if ($stoppedServices.Count -gt 0) { $result.ActionsPerformed += "Stopped Windows Update services ($($stoppedServices -join ', '))" $result.ServicesReset = $true } # Step 2: Fix Dynamic Updates registry configuration Write-WULog -Message "Step 2: Applying Dynamic Updates registry fixes..." -LogPath $LogPath try { # Create OSUpgrade registry path if it doesn't exist $osUpgradePath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\OSUpgrade" if (-not (Test-Path $osUpgradePath)) { New-Item -Path $osUpgradePath -Force | Out-Null Write-WULog -Message "Created OSUpgrade registry path" -LogPath $LogPath } # Add CopyFileBufferedSynchronousIo fix for 24H2 compatibility New-ItemProperty -Path $osUpgradePath -Name "CopyFileBufferedSynchronousIo" -Value 1 -PropertyType DWord -Force | Out-Null Write-WULog -Message "Applied CopyFileBufferedSynchronousIo registry fix" -LogPath $LogPath $result.ActionsPerformed += "Applied CopyFileBufferedSynchronousIo registry fix" $result.RegistryFixed = $true $result.IssuesResolved++ # Ensure AllowOSUpgrade is enabled New-ItemProperty -Path $osUpgradePath -Name "AllowOSUpgrade" -Value 1 -PropertyType DWord -Force | Out-Null Write-WULog -Message "Enabled AllowOSUpgrade registry setting" -LogPath $LogPath # Fix ReservationsAllowed for Windows 11 24H2 New-ItemProperty -Path $osUpgradePath -Name "ReservationsAllowed" -Value 1 -PropertyType DWord -Force | Out-Null Write-WULog -Message "Enabled ReservationsAllowed for Windows 11 24H2" -LogPath $LogPath } catch { Write-WULog -Message "Error applying registry fixes: $($_.Exception.Message)" -Level Error -LogPath $LogPath $result.ErrorMessage = "Registry fix failed: $($_.Exception.Message)" } # Step 3: Clear Windows Update cache and components Write-WULog -Message "Step 3: Clearing Windows Update cache components..." -LogPath $LogPath try { # Remove SoftwareDistribution folder $softwareDistPath = "C:\Windows\SoftwareDistribution" if (Test-Path $softwareDistPath) { $distSize = (Get-ChildItem -Path $softwareDistPath -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum Remove-Item -Path $softwareDistPath -Recurse -Force -ErrorAction Stop Write-WULog -Message "Removed SoftwareDistribution folder ($([math]::Round($distSize / 1MB, 1)) MB)" -LogPath $LogPath $result.ActionsPerformed += "Cleared SoftwareDistribution cache" $result.ComponentsCleared = $true $result.IssuesResolved++ } # Remove catroot2 folder $catroot2Path = "C:\Windows\System32\catroot2" if (Test-Path $catroot2Path) { $catrootSize = (Get-ChildItem -Path $catroot2Path -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum Remove-Item -Path $catroot2Path -Recurse -Force -ErrorAction Stop Write-WULog -Message "Removed catroot2 folder ($([math]::Round($catrootSize / 1MB, 1)) MB)" -LogPath $LogPath $result.ActionsPerformed += "Cleared catroot2 cache" } } catch { Write-WULog -Message "Error clearing Windows Update cache: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 4: Clear Dynamic Updates specific cache Write-WULog -Message "Step 4: Clearing Dynamic Updates specific cache..." -LogPath $LogPath try { $duCachePaths = @( "$env:WINDIR\SoftwareDistribution\Download", "$env:WINDIR\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache", "$env:WINDIR\Temp\MoSetup" ) foreach ($cachePath in $duCachePaths) { if (Test-Path $cachePath) { try { $cacheFiles = Get-ChildItem -Path $cachePath -Force -ErrorAction SilentlyContinue if ($cacheFiles) { Remove-Item -Path "$cachePath\*" -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "Cleared Dynamic Updates cache: $cachePath" -LogPath $LogPath } } catch { Write-WULog -Message "Could not clear all files in $cachePath" -Level Warning -LogPath $LogPath } } } $result.ActionsPerformed += "Cleared Dynamic Updates cache files" } catch { Write-WULog -Message "Error clearing Dynamic Updates cache: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 5: Reset Windows Update Agent authorization Write-WULog -Message "Step 5: Resetting Windows Update Agent authorization..." -LogPath $LogPath try { # Reset authorization tokens & cmd.exe /c "net stop wuauserv" 2>&1 | Out-Null & cmd.exe /c "net stop bits" 2>&1 | Out-Null # Remove authorization cache $authCachePath = "$env:WINDIR\SoftwareDistribution\AuthCabs" if (Test-Path $authCachePath) { Remove-Item -Path $authCachePath -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "Cleared Windows Update authorization cache" -LogPath $LogPath } $result.ActionsPerformed += "Reset Windows Update Agent authorization" } catch { Write-WULog -Message "Error resetting Windows Update authorization: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 6: Re-register Windows Update DLLs related to Dynamic Updates Write-WULog -Message "Step 6: Re-registering Dynamic Updates related DLLs..." -LogPath $LogPath try { $duDlls = @( 'wuapi.dll', 'wuaueng.dll', 'wuaueng1.dll', 'wucltui.dll', 'wups.dll', 'wups2.dll', 'wuweb.dll' ) $registeredCount = 0 Push-Location "$env:WINDIR\System32" foreach ($dll in $duDlls) { try { & regsvr32.exe $dll /s if ($LASTEXITCODE -eq 0) { $registeredCount++ } } catch { Write-WULog -Message "Failed to register $dll" -Level Warning -LogPath $LogPath } } Pop-Location Write-WULog -Message "Re-registered $registeredCount/$($duDlls.Count) Dynamic Updates DLLs" -LogPath $LogPath $result.ActionsPerformed += "Re-registered Dynamic Updates DLLs" } catch { Write-WULog -Message "Error re-registering DLLs: $($_.Exception.Message)" -Level Warning -LogPath $LogPath Pop-Location } # Step 7: Fix Group Policy interference Write-WULog -Message "Step 7: Checking for Group Policy interference..." -LogPath $LogPath try { $gpoUpdatePath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" if (Test-Path $gpoUpdatePath) { # Check for policies that might block Dynamic Updates $problematicPolicies = @( "DoNotConnectToWindowsUpdateInternetLocations", "DisableWindowsUpdateAccess", "NoAutoUpdate" ) foreach ($policy in $problematicPolicies) { $policyValue = Get-ItemProperty -Path $gpoUpdatePath -Name $policy -ErrorAction SilentlyContinue if ($policyValue -and $policyValue.$policy -eq 1) { Write-WULog -Message "Found potentially blocking Group Policy: $policy" -Level Warning -LogPath $LogPath # Don't automatically change GPO settings, just log them } } # Check AU path for Dynamic Updates blocks $auPath = "$gpoUpdatePath\AU" if (Test-Path $auPath) { $noAutoUpdate = Get-ItemProperty -Path $auPath -Name "NoAutoUpdate" -ErrorAction SilentlyContinue if ($noAutoUpdate -and $noAutoUpdate.NoAutoUpdate -eq 1) { Write-WULog -Message "Automatic Updates are disabled via Group Policy - this may block Dynamic Updates" -Level Warning -LogPath $LogPath } } } $result.ActionsPerformed += "Checked Group Policy configuration" } catch { Write-WULog -Message "Error checking Group Policy: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 8: Restart Windows Update services Write-WULog -Message "Step 8: Restarting Windows Update services..." -LogPath $LogPath $restartedServices = @() foreach ($service in $services) { try { $serviceObj = Get-Service -Name $service -ErrorAction SilentlyContinue if ($serviceObj -and $serviceObj.Status -eq 'Stopped') { Start-Service -Name $service -ErrorAction Stop $restartedServices += $service Write-WULog -Message "Started service: $service" -LogPath $LogPath } } catch { Write-WULog -Message "Failed to start service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } if ($restartedServices.Count -gt 0) { $result.ActionsPerformed += "Restarted Windows Update services ($($restartedServices -join ', '))" } # Step 9: Trigger Windows Update detection to test Dynamic Updates Write-WULog -Message "Step 9: Testing Dynamic Updates functionality..." -LogPath $LogPath try { # Use USOClient to trigger a detection scan & USOClient.exe StartInteractiveScan 2>&1 | Out-Null if ($LASTEXITCODE -eq 0) { Write-WULog -Message "Triggered Windows Update detection scan" -LogPath $LogPath $result.ActionsPerformed += "Triggered update detection test" } } catch { Write-WULog -Message "Could not trigger update detection: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Determine overall success if ($result.RegistryFixed -and $result.ComponentsCleared -and $result.ActionsPerformed.Count -gt 0) { $result.Success = $true Write-WULog -Message "Dynamic Updates issues remediation completed successfully" -LogPath $LogPath } } catch { $result.ErrorMessage = $_.Exception.Message Write-WULog -Message "Critical error during Dynamic Updates remediation: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Summary Write-WULog -Message "Dynamic Updates remediation summary:" -LogPath $LogPath Write-WULog -Message " Success: $($result.Success)" -LogPath $LogPath Write-WULog -Message " Registry fixed: $($result.RegistryFixed)" -LogPath $LogPath Write-WULog -Message " Components cleared: $($result.ComponentsCleared)" -LogPath $LogPath Write-WULog -Message " Services reset: $($result.ServicesReset)" -LogPath $LogPath Write-WULog -Message " Issues resolved: $($result.IssuesResolved)" -LogPath $LogPath if ($result.ActionsPerformed.Count -gt 0) { Write-WULog -Message "Actions completed:" -LogPath $LogPath foreach ($action in $result.ActionsPerformed) { Write-WULog -Message " - $action" -LogPath $LogPath } } if ($result.Success) { Write-WULog -Message "RECOMMENDATION: Try Windows 11 24H2 upgrade again - Dynamic Updates should now work properly" -LogPath $LogPath } return $result } |