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 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
        $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,

        [switch]$PassThru,

        [string]$LogPath
    )

    begin {
        # Check for administrator privileges
        $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."
        }

        # Initialize logging
        if (-not $LogPath) {
            $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
            $LogPath = Join-Path $OutputPath "WU-Repair-$timestamp.log"
        }

        # Initialize the repair results object
        $results = [PSCustomObject]@{
            Success = $false
            RebootRequired = $false
            ActionsPerformed = @()
            IssuesResolved = 0
            Errors = @()
            ComponentResults = @{}
            RepairDate = Get-Date
            LogPath = $LogPath
        }

        # Start logging
        Write-WULog -Message "=== Windows Update Repair Started ===" -LogPath $LogPath
        Write-WULog -Message "Version: $script:ModuleVersion" -LogPath $LogPath
        Write-WULog -Message "Parameters: OutputPath=$OutputPath, Comprehensive=$Comprehensive, ComponentStore=$ComponentStore, Services=$Services, SystemPartition=$SystemPartition" -LogPath $LogPath

        $totalErrors = 0
    }

    process {
        try {
            Write-Progress -Activity "Windows Update Repair" -Status "Initializing repair operations..." -PercentComplete 5

            # Determine repair strategy
            if ($PSCmdlet.ParameterSetName -eq 'Comprehensive' -or $Comprehensive) {
                Write-WULog -Message "Starting comprehensive Windows Update repair" -LogPath $LogPath
                Write-Verbose "Executing comprehensive repair strategy"
                
                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 {
                    $errorMsg = "Comprehensive repair failed: $($_.Exception.Message)"
                    Write-WULog -Message $errorMsg -Level Error -LogPath $LogPath
                    $results.Errors += $errorMsg
                    $totalErrors++
                }
            }
            else {
                # Targeted repairs
                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
                    Write-Verbose "Executing Component Store repair"
                    
                    try {
                        $componentResult = Resolve-WUComponentStore -LogPath $LogPath
                        $results.ComponentResults["ComponentStore"] = $componentResult
                        
                        if ($componentResult.Success) {
                            $results.ActionsPerformed += "Component Store Repair"
                            $results.IssuesResolved++
                            if ($componentResult.RebootRequired) {
                                $results.RebootRequired = $true
                            }
                        }
                        $repairCount++
                    }
                    catch {
                        $errorMsg = "Component Store repair failed: $($_.Exception.Message)"
                        Write-WULog -Message $errorMsg -Level Error -LogPath $LogPath
                        $results.Errors += $errorMsg
                        $totalErrors++
                    }
                }

                if ($Services) {
                    Write-Progress -Activity "Windows Update Repair" -Status "Repairing Windows Update Services..." -PercentComplete 50
                    Write-Verbose "Executing Windows Update Services repair"
                    
                    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 {
                        $errorMsg = "Windows Update Services repair failed: $($_.Exception.Message)"
                        Write-WULog -Message $errorMsg -Level Error -LogPath $LogPath
                        $results.Errors += $errorMsg
                        $totalErrors++
                    }
                }

                if ($SystemPartition) {
                    Write-Progress -Activity "Windows Update Repair" -Status "Cleaning System Reserved Partition..." -PercentComplete 75
                    Write-Verbose "Executing System Reserved Partition cleanup"
                    
                    try {
                        $partitionResult = Resolve-WUSystemPartition -LogPath $LogPath
                        $results.ComponentResults["SystemPartition"] = $partitionResult
                        
                        if ($partitionResult.Success) {
                            $results.ActionsPerformed += "System Reserved Partition Cleanup"
                            $results.IssuesResolved++
                        }
                        $repairCount++
                    }
                    catch {
                        $errorMsg = "System Reserved Partition cleanup failed: $($_.Exception.Message)"
                        Write-WULog -Message $errorMsg -Level Error -LogPath $LogPath
                        $results.Errors += $errorMsg
                        $totalErrors++
                    }
                }

                # If no specific repairs were requested, default to comprehensive
                if ($repairCount -eq 0) {
                    Write-WULog -Message "No specific repair requested, defaulting to comprehensive repair" -LogPath $LogPath
                    Write-Verbose "No targeted repairs specified, executing comprehensive repair"
                    
                    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 {
                        $errorMsg = "Comprehensive repair failed: $($_.Exception.Message)"
                        Write-WULog -Message $errorMsg -Level Error -LogPath $LogPath
                        $results.Errors += $errorMsg
                        $totalErrors++
                    }
                }
            }

            Write-Progress -Activity "Windows Update Repair" -Status "Finalizing repair operations..." -PercentComplete 95

            # Determine overall success
            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  # Partial success
            }

        }
        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
        }
    }

    end {
        # Generate summary
        Write-WULog -Message "=== REPAIR SUMMARY ===" -LogPath $LogPath
        Write-WULog -Message "Repair Success: $($results.Success)" -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 ($action in $results.ActionsPerformed) {
                Write-WULog -Message " - $action" -LogPath $LogPath
            }
        }

        if ($results.Errors.Count -gt 0) {
            Write-WULog -Message "ERRORS ENCOUNTERED:" -LogPath $LogPath
            foreach ($error in $results.Errors) {
                Write-WULog -Message " - $error" -Level Error -LogPath $LogPath
            }
        }

        Write-WULog -Message "Log file saved to: $LogPath" -LogPath $LogPath
        Write-WULog -Message "=== Windows Update Repair Completed ===" -LogPath $LogPath

        # Display summary to host
        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.RebootRequired) {
            Write-Host "REBOOT REQUIRED: Some repairs require system restart to complete" -ForegroundColor Yellow
        }

        Write-Host "Log file: $LogPath" -ForegroundColor Gray

        # Return results if PassThru requested
        if ($PassThru) {
            return $results
        }

        # Set exit code based on results
        if ($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
        }
    }
}