dist/temp/WindowsUpdateTools/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 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 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 -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]$DriverCleanup, [Parameter(ParameterSetName = 'Targeted')] [ValidateSet('Identify', 'DisableDevice', 'UninstallDriver')] [string]$DriverCleanupAction, [Parameter(ParameterSetName = 'Targeted')] [switch]$AppraiserIssues, [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' } Write-WULog -Message "Parameters: OutputPath=$OutputPath, Comprehensive=$Comprehensive, ComponentStore=$ComponentStore, Services=$Services, SystemPartition=$SystemPartition, DiskCleanup=$DiskCleanup, 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 $DriverCleanup -or $AppraiserIssues)) { 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 ($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 ($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 } } |