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
}