Public/Repair-WindowsUpdate.ps1
|
function Repair-WindowsUpdate { <# .SYNOPSIS Performs automated Windows Update remediation and repair operations. .DESCRIPTION Repair-WindowsUpdate executes a comprehensive set of Windows Update repair operations to resolve common issues and failures. This function combines multiple remediation strategies based on detected issues or can run comprehensive repairs. .PARAMETER OutputPath Specifies the directory path where log files will be created. Default: C:\Windows\Temp .PARAMETER Comprehensive Run comprehensive remediation that includes all available repair strategies. Use this when the specific issue is unclear or multiple problems are suspected. .PARAMETER ComponentStore Specifically repair Windows Component Store corruption using DISM and SFC. .PARAMETER Services Reset and repair Windows Update services, cache folders, and DLL registration. .PARAMETER SystemPartition Clean up System Reserved Partition to resolve disk space issues. .PARAMETER DiskCleanup Perform enhanced disk cleanup to free space for Windows Updates. Cleans temporary files, caches, and performs WinSxS cleanup. .PARAMETER ClearCache Clear Windows Update download cache. Use this when downloads are stuck, corrupted, or showing incorrect sizes. Stops WU services, clears the SoftwareDistribution\Download folder, and restarts services. .PARAMETER DriverCleanup Identify and remediate problematic drivers that may interfere with Windows Updates. Scans for Windows Setup blocking drivers and device configuration errors. Default action is 'UninstallDriver' which removes and reinstalls problematic drivers. .PARAMETER DriverCleanupAction Specifies the action to take for blocking drivers when -DriverCleanup is used: - 'Identify': Only identify and log problematic drivers - 'DisableDevice': Disable devices associated with blocking drivers - 'UninstallDriver' (default when -DriverCleanup is used): Remove problematic driver packages and reinstall Note: False positive drivers (signed drivers incorrectly flagged) are handled safely. .PARAMETER GroupPolicy Temporarily resolve Group Policy interference with Windows Update operations. Creates a backup of current policies, allows updates to install, then provides instructions for restoring original policy configuration. Use this when updates report success but aren't actually installed due to policy blocking. .PARAMETER PassThru Return detailed results as PowerShell objects for further analysis. When not specified, only writes to host and log file. .PARAMETER LogPath Specifies a custom path for the log file. If not provided, automatically generates a timestamped log file in OutputPath. .EXAMPLE Repair-WindowsUpdate Performs comprehensive Windows Update repair with all available strategies. .EXAMPLE Repair-WindowsUpdate -Services -ComponentStore Performs targeted Windows Update service and component store repair. .EXAMPLE Repair-WindowsUpdate -DiskCleanup -DriverCleanup Performs disk cleanup and removes/reinstalls problematic drivers to resolve space and compatibility issues. .EXAMPLE Repair-WindowsUpdate -ClearCache Clears the Windows Update download cache to fix stuck downloads or corrupted cache showing wrong sizes. .EXAMPLE Repair-WindowsUpdate -DriverCleanup -DriverCleanupAction Identify Identifies Windows Setup blocking drivers without taking remediation action. .EXAMPLE Repair-WindowsUpdate -DriverCleanup -DriverCleanupAction DisableDevice Identifies Windows Setup blocking drivers and disables associated devices. .EXAMPLE Repair-WindowsUpdate -DriverCleanup Identifies and removes/reinstalls problematic driver packages (default action). Signed drivers flagged as false positives are handled safely. .EXAMPLE $results = Repair-WindowsUpdate -Comprehensive -PassThru if ($results.RebootRequired) { Write-Warning "System restart required to complete repairs" } Performs comprehensive repair and checks if reboot is needed. .EXAMPLE Repair-WindowsUpdate -SystemPartition -OutputPath "C:\Logs" -Verbose Performs System Reserved Partition cleanup with verbose logging. .OUTPUTS When -PassThru is specified, returns a PSCustomObject with: - Success: Boolean indicating if repairs were successful - RebootRequired: Boolean indicating if system restart is needed - ActionsPerformed: Array of repair actions that were executed - IssuesResolved: Count of issues that were resolved - Errors: Array of any errors encountered during repair - LogPath: Path to the detailed log file .NOTES Name: Repair-WindowsUpdate Author: Anthony Balloi - CSOLVE Version: 1.0.0 Requires Administrator privileges for repair operations. Some repairs may require system restart to complete. Always review log files for detailed repair information. #> [CmdletBinding(DefaultParameterSetName = 'Comprehensive')] param( [Parameter(Position = 0)] [ValidateScript({ Test-Path $_ -PathType Container })] [string]$OutputPath = $script:DefaultOutputPath, [Parameter(ParameterSetName = 'Comprehensive')] [switch]$Comprehensive, [Parameter(ParameterSetName = 'Targeted')] [switch]$ComponentStore, [Parameter(ParameterSetName = 'Targeted')] [switch]$Services, [Parameter(ParameterSetName = 'Targeted')] [switch]$SystemPartition, [Parameter(ParameterSetName = 'Targeted')] [switch]$DiskCleanup, [Parameter(ParameterSetName = 'Targeted')] [switch]$ClearCache, [Parameter(ParameterSetName = 'Targeted')] [switch]$DriverCleanup, [Parameter(ParameterSetName = 'Targeted')] [ValidateSet('Identify', 'DisableDevice', 'UninstallDriver')] [string]$DriverCleanupAction, [Parameter(ParameterSetName = 'Targeted')] [switch]$AppraiserIssues, [Parameter(ParameterSetName = 'Targeted')] [switch]$GroupPolicy, [switch]$PassThru, [Parameter(ParameterSetName = 'Targeted')] [switch]$Diagnostics, [string]$RepairSource, [int]$DiagnosticsTail = 800, [switch]$DiagnosticsFull, [switch]$DiagnosticsIncludeSFC, [string]$LogPath ) # Single-block implementation (begin/process/end consolidated) # Admin check $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw 'Repair-WindowsUpdate requires Administrator privileges. Please run PowerShell as Administrator.' } if (-not $LogPath) { $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $LogPath = Join-Path $OutputPath "WU-Repair-$timestamp.log" } $results = [PSCustomObject]@{ Success = $false RebootRequired = $false ActionsPerformed = @() IssuesResolved = 0 Errors = @() ComponentResults = @{} RepairDate = Get-Date LogPath = $LogPath SevereError = $false Diagnostics = $null } Write-WULog -Message '=== Windows Update Repair Started ===' -LogPath $LogPath Write-WULog -Message "Version: $script:ModuleVersion" -LogPath $LogPath if ($DriverCleanup -and -not $PSBoundParameters.ContainsKey('DriverCleanupAction')) { $DriverCleanupAction = 'UninstallDriver' } elseif (-not $PSBoundParameters.ContainsKey('DriverCleanupAction')) { $DriverCleanupAction = 'Identify' } # Log parameters based on mode if ($Comprehensive) { Write-WULog -Message "Mode: COMPREHENSIVE (runs all repair operations in sequence)" -LogPath $LogPath Write-WULog -Message "Parameters: OutputPath=$OutputPath, RepairSource=$RepairSource, Diagnostics=$Diagnostics, DiagnosticsFull=$DiagnosticsFull" -LogPath $LogPath } else { Write-WULog -Message "Mode: TARGETED (individual repair operations)" -LogPath $LogPath Write-WULog -Message "Parameters: OutputPath=$OutputPath, ComponentStore=$ComponentStore, Services=$Services, SystemPartition=$SystemPartition, DiskCleanup=$DiskCleanup, ClearCache=$ClearCache, DriverCleanup=$DriverCleanup, DriverCleanupAction=$DriverCleanupAction, RepairSource=$RepairSource, Diagnostics=$Diagnostics, DiagnosticsFull=$DiagnosticsFull, DiagnosticsTail=$DiagnosticsTail, DiagnosticsIncludeSFC=$DiagnosticsIncludeSFC" -LogPath $LogPath } if ($Diagnostics) { Write-WULog -Message 'Diagnostics collection enabled' -LogPath $LogPath } if ($RepairSource) { Write-WULog -Message "RepairSource specified: $RepairSource" -LogPath $LogPath } $totalErrors = 0 # Direct component store repair mode - skip Windows Update installation if ($PSCmdlet.ParameterSetName -eq 'Targeted' -and $ComponentStore -and -not ($Services -or $SystemPartition -or $DiskCleanup -or $ClearCache -or $DriverCleanup -or $AppraiserIssues -or $GroupPolicy)) { Write-WULog -Message '=== DIRECT COMPONENT STORE REPAIR MODE ===' -LogPath $LogPath Write-WULog -Message 'Skipping Windows Update installation - proceeding directly to component store repair with ISO download capability' -LogPath $LogPath try { Write-Progress -Activity 'Windows Update Repair' -Status 'Component Store Analysis and Repair...' -PercentComplete 50 $componentResult = Resolve-WUComponentStore -LogPath $LogPath -RepairSource $RepairSource $results.ComponentResults['ComponentStore'] = $componentResult if ($componentResult.Success) { $results.ActionsPerformed += $componentResult.ActionsPerformed $results.IssuesResolved += $componentResult.IssuesResolved if ($componentResult.RebootRequired) { $results.RebootRequired = $true } $results.Success = $true Write-WULog -Message 'Direct component store repair completed successfully' -LogPath $LogPath } else { Write-WULog -Message 'Component store repair failed or requires manual intervention' -LogPath $LogPath -Level Warning if ($componentResult.SevereError) { $results.SevereError = $true Write-WULog -Message 'Severe component store error detected' -LogPath $LogPath -Level Error } } } catch { $msg = "Direct component store repair failed: $($_.Exception.Message)" Write-WULog -Message $msg -Level Error -LogPath $LogPath $results.Errors += $msg $totalErrors++ } # Skip the rest of the repair logic and go directly to summary Write-Progress -Activity 'Windows Update Repair' -Completed Write-WULog -Message '=== DIRECT COMPONENT STORE REPAIR SUMMARY ===' -LogPath $LogPath Write-WULog -Message "Repair Success: $($results.Success) (SevereError=$($results.SevereError))" -LogPath $LogPath Write-WULog -Message "Actions Performed: $($results.ActionsPerformed.Count)" -LogPath $LogPath Write-WULog -Message "Issues Resolved: $($results.IssuesResolved)" -LogPath $LogPath Write-WULog -Message "Errors Encountered: $($results.Errors.Count)" -LogPath $LogPath Write-WULog -Message "Reboot Required: $($results.RebootRequired)" -LogPath $LogPath if ($results.ActionsPerformed.Count -gt 0) { Write-WULog -Message 'ACTIONS PERFORMED:' -LogPath $LogPath foreach ($a in $results.ActionsPerformed) { Write-WULog -Message " - $a" -LogPath $LogPath } } if ($results.Errors.Count -gt 0) { Write-WULog -Message 'ERRORS ENCOUNTERED:' -LogPath $LogPath foreach ($e in $results.Errors) { Write-WULog -Message " - $e" -Level Error -LogPath $LogPath } } Write-WULog -Message '=== Direct Component Store Repair Completed ===' -LogPath $LogPath Write-Host "`n=== Direct Component Store Repair Results ===" -ForegroundColor Cyan if ($results.Success) { Write-Host 'Repair Status: SUCCESS' -ForegroundColor Green Write-Host "Actions Performed: $($results.ActionsPerformed.Count)" -ForegroundColor Green Write-Host "Issues Resolved: $($results.IssuesResolved)" -ForegroundColor Green } else { Write-Host 'Repair Status: PARTIAL/FAILED' -ForegroundColor Red Write-Host "Errors: $($results.Errors.Count)" -ForegroundColor Red if ($results.SevereError) { Write-Host 'Severe Component Store Error Detected' -ForegroundColor Red } } if ($results.RebootRequired) { Write-Host 'REBOOT REQUIRED: Component store repairs require system restart to complete' -ForegroundColor Yellow } Write-Host "Log file: $LogPath" -ForegroundColor Gray if ($PassThru) { return $results } if ($results.SevereError) { $global:LASTEXITCODE = $script:ExitCodes.SevereComponentStoreFailure } elseif ($results.Success -and $results.Errors.Count -eq 0) { if ($results.RebootRequired) { $global:LASTEXITCODE = $script:ExitCodes.RebootRequired } else { $global:LASTEXITCODE = $script:ExitCodes.Success } } elseif ($results.Success) { $global:LASTEXITCODE = $script:ExitCodes.PartialSuccess } else { $global:LASTEXITCODE = $script:ExitCodes.Failure } return } try { Write-Progress -Activity 'Windows Update Repair' -Status 'Initializing repair operations...' -PercentComplete 5 if ($PSCmdlet.ParameterSetName -eq 'Comprehensive' -or $Comprehensive) { Write-WULog -Message 'Starting comprehensive Windows Update repair' -LogPath $LogPath try { $comprehensiveResult = Invoke-WUComprehensiveRemediation -LogPath $LogPath $results.ComponentResults['Comprehensive'] = $comprehensiveResult if ($comprehensiveResult.Success) { $results.ActionsPerformed += $comprehensiveResult.ActionsPerformed $results.IssuesResolved += $comprehensiveResult.IssuesResolved if ($comprehensiveResult.RebootRequired) { $results.RebootRequired = $true } } } catch { $msg = "Comprehensive repair failed: $($_.Exception.Message)" Write-WULog -Message $msg -Level Error -LogPath $LogPath $results.Errors += $msg; $totalErrors++ } } else { Write-WULog -Message 'Starting targeted Windows Update repairs' -LogPath $LogPath $repairCount = 0 if ($ComponentStore) { Write-Progress -Activity 'Windows Update Repair' -Status 'Repairing Component Store...' -PercentComplete 25 try { $componentResult = Resolve-WUComponentStore -LogPath $LogPath -RepairSource $RepairSource $results.ComponentResults['ComponentStore'] = $componentResult if ($componentResult.Success) { $results.ActionsPerformed += 'Component Store Repair' $results.IssuesResolved++ if ($componentResult.RebootRequired) { $results.RebootRequired = $true } } $repairCount++ } catch { $msg = "Component Store repair failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($Services) { Write-Progress -Activity 'Windows Update Repair' -Status 'Repairing Windows Update Services...' -PercentComplete 50 try { $serviceResult = Resolve-WUGenericErrors -LogPath $LogPath $results.ComponentResults['Services'] = $serviceResult if ($serviceResult.Success) { $results.ActionsPerformed += 'Windows Update Services Repair' $results.IssuesResolved++ if ($serviceResult.RebootRequired) { $results.RebootRequired = $true } } $repairCount++ } catch { $msg = "Windows Update Services repair failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($AppraiserIssues) { Write-Progress -Activity 'Windows Update Repair' -Status 'Resolving Appraiser Issues...' -PercentComplete 60 try { $appraiserResult = Resolve-WUAppraiserIssues -LogPath $LogPath $results.ComponentResults['AppraiserIssues'] = $appraiserResult if ($appraiserResult.Success) { $results.ActionsPerformed += 'Appraiser Issues Remediation'; $results.IssuesResolved++ } $repairCount++ } catch { $msg = "Appraiser Issues remediation failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($GroupPolicy) { Write-Progress -Activity 'Windows Update Repair' -Status 'Resolving Group Policy Interference...' -PercentComplete 65 try { Write-WULog -Message '=== GROUP POLICY INTERFERENCE REMEDIATION ===' -LogPath $LogPath Write-WULog -Message 'Temporarily modifying Group Policy settings to allow Windows Update operations' -LogPath $LogPath # Create backup and modify Group Policy settings $backupPath = "$env:TEMP\WindowsUpdate_Policy_Backup_$(Get-Date -Format 'yyyyMMdd_HHmmss').reg" # Export current Group Policy settings Write-WULog -Message "Creating backup of current Group Policy settings at: $backupPath" -LogPath $LogPath $exportPaths = @( "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" ) foreach ($exportPath in $exportPaths) { & reg export $exportPath $backupPath /y 2>$null } # Temporarily modify policies to allow updates $policyPaths = @{ "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" = @{ "NoAutoUpdate" = 0 "AUOptions" = 4 "UseWUServer" = 0 } "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" = @{ "DisableWindowsUpdateAccess" = 0 } } $policiesModified = @() foreach ($registryPath in $policyPaths.Keys) { if (-not (Test-Path $registryPath)) { New-Item -Path $registryPath -Force | Out-Null Write-WULog -Message "Created registry path: $registryPath" -LogPath $LogPath } $values = $policyPaths[$registryPath] foreach ($valueName in $values.Keys) { $newValue = $values[$valueName] Set-ItemProperty -Path $registryPath -Name $valueName -Value $newValue -Type DWord $policiesModified += "${registryPath}\${valueName}" Write-WULog -Message "Set policy value: $valueName = $newValue" -LogPath $LogPath } } # Restart Windows Update service to apply changes Write-WULog -Message 'Restarting Windows Update service to apply policy changes...' -LogPath $LogPath Stop-Service -Name "wuauserv" -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 2 Start-Service -Name "wuauserv" -ErrorAction SilentlyContinue Write-WULog -Message "Group Policy interference resolved. Modified $($policiesModified.Count) policy values." -LogPath $LogPath Write-WULog -Message "" -LogPath $LogPath Write-WULog -Message "IMPORTANT: After Windows Update operations complete, restore original policies:" -LogPath $LogPath -Level Warning Write-WULog -Message " reg import `"$backupPath`"" -LogPath $LogPath -Level Warning Write-WULog -Message "" -LogPath $LogPath $groupPolicyResult = @{ Success = $true BackupPath = $backupPath PoliciesModified = $policiesModified RestoreCommand = "reg import `"$backupPath`"" } $results.ComponentResults['GroupPolicy'] = $groupPolicyResult $results.ActionsPerformed += 'Group Policy Interference Remediation' $results.IssuesResolved++ $repairCount++ } catch { $msg = "Group Policy remediation failed: $($_.Exception.Message)" Write-WULog -Message $msg -Level Error -LogPath $LogPath $results.Errors += $msg $totalErrors++ } } if ($SystemPartition) { Write-Progress -Activity 'Windows Update Repair' -Status 'Cleaning System Reserved Partition...' -PercentComplete 75 try { $partitionResult = Resolve-WUSystemPartition -LogPath $LogPath $results.ComponentResults['SystemPartition'] = $partitionResult if ($partitionResult.Success) { $results.ActionsPerformed += 'System Reserved Partition Cleanup'; $results.IssuesResolved++ } $repairCount++ } catch { $msg = "System Reserved Partition cleanup failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($DiskCleanup) { Write-Progress -Activity 'Windows Update Repair' -Status 'Performing enhanced disk cleanup...' -PercentComplete 80 try { $diskCleanupResult = Invoke-WUEnhancedDiskCleanup -LogPath $LogPath $results.ComponentResults['DiskCleanup'] = $diskCleanupResult if ($diskCleanupResult.Success) { $results.ActionsPerformed += 'Enhanced Disk Cleanup'; $results.IssuesResolved++ } $repairCount++ } catch { $msg = "Enhanced disk cleanup failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($ClearCache) { Write-Progress -Activity 'Windows Update Repair' -Status 'Clearing Windows Update download cache...' -PercentComplete 82 try { Write-WULog -Message '=== CLEARING WINDOWS UPDATE DOWNLOAD CACHE ===' -LogPath $LogPath Write-WULog -Message 'This resolves stuck downloads, corrupted cache, and incorrect download sizes' -LogPath $LogPath # Stop Windows Update services $servicesToStop = @('wuauserv', 'bits', 'cryptsvc') foreach ($svc in $servicesToStop) { Write-WULog -Message "Stopping service: $svc" -LogPath $LogPath Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 3 # Clear download cache $downloadPath = "$env:SystemRoot\SoftwareDistribution\Download" if (Test-Path $downloadPath) { $itemsBefore = (Get-ChildItem -Path $downloadPath -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object).Count $sizeBefore = (Get-ChildItem -Path $downloadPath -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum $sizeMB = [math]::Round($sizeBefore / 1MB, 1) Write-WULog -Message "Download cache: $itemsBefore items, $sizeMB MB" -LogPath $LogPath Remove-Item -Path "$downloadPath\*" -Recurse -Force -ErrorAction SilentlyContinue $itemsAfter = (Get-ChildItem -Path $downloadPath -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object).Count Write-WULog -Message "Cache cleared: removed $($itemsBefore - $itemsAfter) items ($sizeMB MB freed)" -LogPath $LogPath } else { Write-WULog -Message "Download cache path not found: $downloadPath" -Level Warning -LogPath $LogPath } # Also clear the DataStore folder which contains the WU database $dataStorePath = "$env:SystemRoot\SoftwareDistribution\DataStore" if (Test-Path $dataStorePath) { Remove-Item -Path "$dataStorePath\*" -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "DataStore cache cleared" -LogPath $LogPath } # Fix stale Orchestrator registry (common after feature updates, causes UUP issues) try { $actualBuild = [int](Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -ErrorAction SilentlyContinue).CurrentBuild $actualUBR = [int](Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -ErrorAction SilentlyContinue).UBR $orchestratorBuild = [int](Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler" -ErrorAction SilentlyContinue).LastKnownBuildNumber if ($actualBuild -and $orchestratorBuild -and $actualBuild -ne $orchestratorBuild) { Write-WULog -Message "Fixing stale Orchestrator registry: Orchestrator=$orchestratorBuild, Actual=$actualBuild.$actualUBR" -LogPath $LogPath Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler" -Name "LastKnownBuildNumber" -Value $actualBuild -ErrorAction SilentlyContinue Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler" -Name "LastKnownUBR" -Value $actualUBR -ErrorAction SilentlyContinue Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\OSUpgrade" -Name "BuildString" -Value "10.0.$actualBuild.$actualUBR" -ErrorAction SilentlyContinue Write-WULog -Message "Orchestrator registry updated to match current OS build" -LogPath $LogPath $results.ActionsPerformed += "Fixed stale Orchestrator registry (was $orchestratorBuild, now $actualBuild)" } } catch { Write-WULog -Message "Could not check/fix Orchestrator registry: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Restart services foreach ($svc in $servicesToStop) { Write-WULog -Message "Starting service: $svc" -LogPath $LogPath Start-Service -Name $svc -ErrorAction SilentlyContinue } Write-WULog -Message 'Windows Update download cache cleared successfully' -LogPath $LogPath Write-WULog -Message 'Run Get-PendingUpdates to re-check for updates with correct sizes' -LogPath $LogPath $cacheResult = @{ Success = $true ItemsRemoved = $itemsBefore - $itemsAfter SpaceFreedMB = $sizeMB } $results.ComponentResults['ClearCache'] = $cacheResult $results.ActionsPerformed += "Windows Update Cache Cleared ($sizeMB MB freed)" $results.IssuesResolved++ $repairCount++ } catch { $msg = "Clear cache failed: $($_.Exception.Message)" Write-WULog -Message $msg -Level Error -LogPath $LogPath $results.Errors += $msg $totalErrors++ } } if ($DriverCleanup) { Write-Progress -Activity 'Windows Update Repair' -Status 'Cleaning up problematic drivers...' -PercentComplete 85 try { $driverCleanupResult = Remove-WUProblematicDrivers -LogPath $LogPath -RemoveAction $DriverCleanupAction $results.ComponentResults['DriverCleanup'] = $driverCleanupResult if ($driverCleanupResult.Success) { $actionDescription = switch ($DriverCleanupAction) { 'Identify' { 'Driver Analysis' } 'DisableDevice' { 'Driver Cleanup (Devices Disabled)' } 'UninstallDriver' { 'Driver Cleanup (Drivers Removed)' } default { 'Driver Cleanup' } } $results.ActionsPerformed += $actionDescription $results.IssuesResolved++ if ($driverCleanupResult.BlockingDriversFound -gt 0) { $results.ActionsPerformed += "Analyzed $($driverCleanupResult.BlockingDriversFound) Windows Setup blocking drivers" } if ($driverCleanupResult.SignatureDiscrepancies -gt 0) { $results.ActionsPerformed += "Identified $($driverCleanupResult.SignatureDiscrepancies) false positive signature flags" } if ($driverCleanupResult.DriversRemoved -gt 0) { $results.ActionsPerformed += "Removed $($driverCleanupResult.DriversRemoved) problematic drivers" } if ($driverCleanupResult.DriversDisabled -gt 0) { $results.ActionsPerformed += "Disabled $($driverCleanupResult.DriversDisabled) problematic devices" } } $repairCount++ } catch { $msg = "Driver cleanup failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } if ($repairCount -eq 0) { Write-WULog -Message 'No specific repair requested, defaulting to comprehensive repair' -LogPath $LogPath try { $comprehensiveResult = Invoke-WUComprehensiveRemediation -LogPath $LogPath $results.ComponentResults['Comprehensive'] = $comprehensiveResult if ($comprehensiveResult.Success) { $results.ActionsPerformed += $comprehensiveResult.ActionsPerformed $results.IssuesResolved += $comprehensiveResult.IssuesResolved if ($comprehensiveResult.RebootRequired) { $results.RebootRequired = $true } } } catch { $msg = "Comprehensive repair failed: $($_.Exception.Message)"; Write-WULog -Message $msg -Level Error -LogPath $LogPath; $results.Errors += $msg; $totalErrors++ } } } Write-Progress -Activity 'Windows Update Repair' -Status 'Finalizing repair operations...' -PercentComplete 95 foreach ($cr in $results.ComponentResults.GetEnumerator()) { if ($cr.Value -and ($cr.Value.PSObject.Properties.Name -contains 'SevereError') -and $cr.Value.SevereError) { $results.SevereError = $true Write-WULog -Message "Severe error detected in component: $($cr.Key)" -Level Error -LogPath $LogPath } } if (-not $results.SevereError) { if ($results.ActionsPerformed.Count -gt 0 -and $totalErrors -eq 0) { $results.Success = $true } elseif ($results.ActionsPerformed.Count -gt 0 -and $totalErrors -lt $results.ActionsPerformed.Count) { $results.Success = $true } } else { $results.Success = $false } } catch { Write-WULog -Message "Critical error during Windows Update repair: $($_.Exception.Message)" -Level Error -LogPath $LogPath $results.Errors += "Critical error during repair: $($_.Exception.Message)"; $totalErrors++ } finally { Write-Progress -Activity 'Windows Update Repair' -Completed } Write-WULog -Message '=== REPAIR SUMMARY ===' -LogPath $LogPath Write-WULog -Message "Repair Success: $($results.Success) (SevereError=$($results.SevereError))" -LogPath $LogPath Write-WULog -Message "Actions Performed: $($results.ActionsPerformed.Count)" -LogPath $LogPath Write-WULog -Message "Issues Resolved: $($results.IssuesResolved)" -LogPath $LogPath Write-WULog -Message "Errors Encountered: $($results.Errors.Count)" -LogPath $LogPath Write-WULog -Message "Reboot Required: $($results.RebootRequired)" -LogPath $LogPath if ($results.ActionsPerformed.Count -gt 0) { Write-WULog -Message 'ACTIONS PERFORMED:' -LogPath $LogPath; foreach ($a in $results.ActionsPerformed) { Write-WULog -Message " - $a" -LogPath $LogPath } } if ($results.Errors.Count -gt 0) { Write-WULog -Message 'ERRORS ENCOUNTERED:' -LogPath $LogPath; foreach ($e in $results.Errors) { Write-WULog -Message " - $e" -Level Error -LogPath $LogPath } } if ($Diagnostics) { Write-WULog -Message 'Collecting servicing diagnostics...' -LogPath $LogPath try { $diagParams = @{ LogPath = $LogPath } if ($DiagnosticsFull) { $diagParams.Full = $true } else { $diagParams.Tail = $DiagnosticsTail } if ($DiagnosticsIncludeSFC) { $diagParams.IncludeSFCEvents = $true } $diag = Get-ServicingDiagnostics @diagParams $results.Diagnostics = $diag if ($diag.Success) { Write-WULog -Message "Servicing diagnostics collected. Categories=$([string]::Join(',', $diag.Categories))" -LogPath $LogPath } else { Write-WULog -Message 'Servicing diagnostics encountered issues.' -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Failed to collect diagnostics: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } Write-WULog -Message '=== Windows Update Repair Completed ===' -LogPath $LogPath Write-Host "`n=== Windows Update Repair Results ===" -ForegroundColor Cyan if ($results.Success) { Write-Host 'Repair Status: SUCCESS' -ForegroundColor Green Write-Host "Actions Performed: $($results.ActionsPerformed.Count)" -ForegroundColor Green Write-Host "Issues Resolved: $($results.IssuesResolved)" -ForegroundColor Green } else { Write-Host 'Repair Status: PARTIAL/FAILED' -ForegroundColor Red Write-Host "Errors: $($results.Errors.Count)" -ForegroundColor Red if ($results.SevereError) { Write-Host 'Severe Component Store Error Detected' -ForegroundColor Red } } if ($results.RebootRequired) { Write-Host 'REBOOT REQUIRED: Some repairs require system restart to complete' -ForegroundColor Yellow } Write-Host "Log file: $LogPath" -ForegroundColor Gray if ($PassThru) { return $results } if ($results.SevereError) { $global:LASTEXITCODE = $script:ExitCodes.SevereComponentStoreFailure } elseif ($results.Success -and $results.Errors.Count -eq 0) { if ($results.RebootRequired) { $global:LASTEXITCODE = $script:ExitCodes.RebootRequired } else { $global:LASTEXITCODE = $script:ExitCodes.Success } } elseif ($results.Success) { $global:LASTEXITCODE = $script:ExitCodes.PartialSuccess } else { $global:LASTEXITCODE = $script:ExitCodes.Failure } } |