Private/Resolve-WUGenericErrors.ps1
function Resolve-WUGenericErrors { <# .SYNOPSIS Performs generic Windows Update service reset and repair operations. .DESCRIPTION Comprehensive Windows Update service remediation including service reset, cache cleanup, DLL re-registration, and network stack reset. This function implements the "nuclear option" for Windows Update service repair. .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $result = Resolve-WUGenericErrors -LogPath "C:\Logs\wu.log" .NOTES This function requires Administrator privileges. Returns an object with Success, ActionsPerformed, and RebootRequired properties. Performs comprehensive service reset including: - Windows Update service stop/start cycle - Cache folder reset (SoftwareDistribution, CatRoot2) - DLL re-registration - WinSock reset - Service security descriptor reset #> [CmdletBinding()] param( [string]$LogPath ) # Initialize result object $result = [PSCustomObject]@{ Success = $false RebootRequired = $false # Will be set to true if WinSock reset succeeds ActionsPerformed = @() ErrorMessage = $null ServicesRestarted = 0 DllsRegistered = 0 } Write-WULog -Message "Starting generic Windows Update remediation" -LogPath $LogPath try { # Define Windows Update services $services = @('BITS', 'wuauserv', 'cryptsvc', 'msiserver') # Step 1: Stop Windows Update Services Write-WULog -Message "Step 1: Stopping Windows Update Services..." -LogPath $LogPath foreach ($service in $services) { try { $serviceObj = Get-Service -Name $service -ErrorAction SilentlyContinue if ($serviceObj) { if ($serviceObj.Status -eq 'Running') { Write-WULog -Message "Stopping service: $service" -LogPath $LogPath Stop-Service -Name $service -Force -ErrorAction Stop -WarningAction SilentlyContinue Write-WULog -Message "Stopped service: $service" -LogPath $LogPath } else { Write-WULog -Message "Service $service was already stopped" -LogPath $LogPath } } else { Write-WULog -Message "Service $service not found" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Failed to stop service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } $result.ActionsPerformed += "Stopped Windows Update Services" # Step 2: Remove QMGR Data files Write-WULog -Message "Step 2: Removing QMGR Data files..." -LogPath $LogPath try { $qmgrPath = "$env:ProgramData\Microsoft\Network\Downloader" $qmgrFiles = Get-ChildItem -Path "$qmgrPath\qmgr*.dat" -ErrorAction SilentlyContinue if ($qmgrFiles) { $totalSize = ($qmgrFiles | Measure-Object -Property Length -Sum).Sum Remove-Item -Path $qmgrFiles.FullName -Force -ErrorAction SilentlyContinue Write-WULog -Message "Removed $($qmgrFiles.Count) QMGR data files ($([math]::Round($totalSize / 1KB, 1)) KB)" -LogPath $LogPath $result.ActionsPerformed += "Removed QMGR Data Files" } else { Write-WULog -Message "No QMGR data files found" -LogPath $LogPath } } catch { Write-WULog -Message "Error removing QMGR data files: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 3: Rename Software Distribution and CatRoot2 folders Write-WULog -Message "Step 3: Renaming Software Distribution and CatRoot2 folders..." -LogPath $LogPath try { # Handle SoftwareDistribution $sdPath = "$env:systemroot\SoftwareDistribution" $sdOldPath = "$env:systemroot\SoftwareDistribution.old" if (Test-Path $sdOldPath) { Write-WULog -Message "Removing existing SoftwareDistribution.old" -LogPath $LogPath Remove-Item -Path $sdOldPath -Recurse -Force -ErrorAction SilentlyContinue } if (Test-Path $sdPath) { Rename-Item -Path $sdPath -NewName "SoftwareDistribution.old" -ErrorAction Stop Write-WULog -Message "Renamed SoftwareDistribution folder" -LogPath $LogPath } else { Write-WULog -Message "SoftwareDistribution folder not found" -Level Warning -LogPath $LogPath } # Handle CatRoot2 $catroot2Path = "$env:systemroot\System32\Catroot2" $catroot2OldPath = "$env:systemroot\System32\Catroot2.old" if (Test-Path $catroot2OldPath) { Write-WULog -Message "Removing existing Catroot2.old" -LogPath $LogPath Remove-Item -Path $catroot2OldPath -Recurse -Force -ErrorAction SilentlyContinue } if (Test-Path $catroot2Path) { Rename-Item -Path $catroot2Path -NewName "Catroot2.old" -ErrorAction Stop Write-WULog -Message "Renamed Catroot2 folder" -LogPath $LogPath } else { Write-WULog -Message "Catroot2 folder not found" -Level Warning -LogPath $LogPath } $result.ActionsPerformed += "Reset Windows Update Cache Folders" } catch { Write-WULog -Message "Error renaming cache folders: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 4: Reset Windows Update Services to default settings Write-WULog -Message "Step 4: Resetting Windows Update Services to default settings..." -LogPath $LogPath try { # Reset service security descriptors $securityCommands = @( @{ Service = 'bits'; Command = 'sc.exe sdset bits "D:(A;CI;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)"' }, @{ Service = 'wuauserv'; Command = 'sc.exe sdset wuauserv "D:(A;;CCLCSWRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)"' } ) foreach ($secCmd in $securityCommands) { try { $output = Invoke-Expression $secCmd.Command 2>&1 if ($LASTEXITCODE -eq 0) { Write-WULog -Message "Reset security descriptor for $($secCmd.Service)" -LogPath $LogPath } else { Write-WULog -Message "Failed to reset security descriptor for $($secCmd.Service): $output" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Error resetting security descriptor for $($secCmd.Service): $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } $result.ActionsPerformed += "Reset Service Security Descriptors" } catch { Write-WULog -Message "Error resetting service security descriptors: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 5: Re-register DLLs Write-WULog -Message "Step 5: Re-registering DLLs..." -LogPath $LogPath try { Push-Location "$env:systemroot\system32" $dlls = @( 'atl.dll', 'urlmon.dll', 'mshtml.dll', 'shdocvw.dll', 'browseui.dll', 'jscript.dll', 'vbscript.dll', 'scrrun.dll', 'msxml.dll', 'msxml3.dll', 'msxml6.dll', 'actxprxy.dll', 'softpub.dll', 'wintrust.dll', 'dssenh.dll', 'rsaenh.dll', 'gpkcsp.dll', 'sccbase.dll', 'slbcsp.dll', 'cryptdlg.dll', 'oleaut32.dll', 'ole32.dll', 'shell32.dll', 'initpki.dll', 'wuapi.dll', 'wuaueng.dll', 'wuaueng1.dll', 'wucltui.dll', 'wups.dll', 'wups2.dll', 'wuweb.dll', 'qmgr.dll', 'qmgrprxy.dll', 'wucltux.dll', 'muweb.dll', 'wuwebv.dll' ) $registeredCount = 0 $failedCount = 0 foreach ($dll in $dlls) { try { & regsvr32.exe $dll /s 2>&1 | Out-Null if ($LASTEXITCODE -eq 0) { $registeredCount++ } else { $failedCount++ Write-WULog -Message "Failed to register $dll" -Level Warning -LogPath $LogPath } } catch { $failedCount++ Write-WULog -Message "Error registering $dll`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } Write-WULog -Message "Successfully registered $registeredCount/$($dlls.Count) DLLs ($failedCount failed)" -LogPath $LogPath $result.DllsRegistered = $registeredCount $result.ActionsPerformed += "Re-registered Windows Update DLLs" Pop-Location } catch { Write-WULog -Message "Error during DLL registration: $($_.Exception.Message)" -Level Warning -LogPath $LogPath Pop-Location } # Step 6: Reset WinSock Write-WULog -Message "Step 6: Resetting WinSock..." -LogPath $LogPath try { $winsockOutput = & netsh winsock reset 2>&1 if ($LASTEXITCODE -eq 0) { Write-WULog -Message "WinSock reset completed successfully - reboot required" -LogPath $LogPath $result.RebootRequired = $true $result.ActionsPerformed += "WinSock Reset" } else { Write-WULog -Message "WinSock reset failed: $winsockOutput" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Failed to reset WinSock: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 7: Start Windows Update Services Write-WULog -Message "Step 7: Starting Windows Update Services..." -LogPath $LogPath foreach ($service in $services) { try { $serviceObj = Get-Service -Name $service -ErrorAction SilentlyContinue if ($serviceObj) { if ($serviceObj.Status -ne 'Running') { Write-WULog -Message "Starting service: $service" -LogPath $LogPath Start-Service -Name $service -ErrorAction Stop Write-WULog -Message "Started service: $service" -LogPath $LogPath $result.ServicesRestarted++ } else { Write-WULog -Message "Service $service was already running" -LogPath $LogPath } } else { Write-WULog -Message "Service $service not found" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Failed to start service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } $result.ActionsPerformed += "Restarted Windows Update Services" # Step 8: Force Windows Update discovery Write-WULog -Message "Step 8: Forcing Windows Update discovery..." -LogPath $LogPath try { $usoclientOutput = & USOClient.exe StartInteractiveScan 2>&1 if ($LASTEXITCODE -eq 0) { Write-WULog -Message "Windows Update discovery initiated successfully" -LogPath $LogPath $result.ActionsPerformed += "Initiated Windows Update Discovery" } else { Write-WULog -Message "Failed to start update discovery: $usoclientOutput" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Failed to start update discovery: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 9: Additional cleanup - Remove temporary internet files and Windows Update logs Write-WULog -Message "Step 9: Additional cleanup..." -LogPath $LogPath try { # Clean Windows Update logs that might be corrupted $wuLogPaths = @( "$env:systemroot\WindowsUpdate.log", "$env:systemroot\SoftwareDistribution\ReportingEvents.log" ) foreach ($logPath in $wuLogPaths) { if (Test-Path $logPath) { try { Remove-Item -Path $logPath -Force -ErrorAction Stop Write-WULog -Message "Removed potentially corrupted log: $logPath" -LogPath $LogPath } catch { Write-WULog -Message "Could not remove log file $logPath`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } $result.ActionsPerformed += "Cleaned Windows Update Logs" } catch { Write-WULog -Message "Error during additional cleanup: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Determine overall success if ($result.ActionsPerformed.Count -gt 0) { $result.Success = $true } } catch { $result.ErrorMessage = $_.Exception.Message Write-WULog -Message "Critical error during generic Windows Update remediation: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Summary if ($result.Success) { Write-WULog -Message "Generic Windows Update remediation completed successfully" -LogPath $LogPath Write-WULog -Message "Actions performed:" -LogPath $LogPath foreach ($action in $result.ActionsPerformed) { Write-WULog -Message " - $action" -LogPath $LogPath } Write-WULog -Message "Services restarted: $($result.ServicesRestarted)" -LogPath $LogPath Write-WULog -Message "DLLs registered: $($result.DllsRegistered)" -LogPath $LogPath if ($result.RebootRequired) { Write-WULog -Message "REBOOT REQUIRED: WinSock reset requires system restart" -Level Warning -LogPath $LogPath } } else { Write-WULog -Message "Generic Windows Update remediation failed: $($result.ErrorMessage)" -Level Error -LogPath $LogPath } return $result } |