Private/Resolve-WUComponentStore.ps1
|
function Resolve-WUComponentStore { <# .SYNOPSIS Repairs Windows Component Store corruption issues using advanced community techniques. .DESCRIPTION Performs comprehensive Component Store health assessment and repair using DISM and System File Checker (SFC) tools. Includes advanced community-sourced techniques for addressing stubborn corruption issues that standard Microsoft methods often fail to resolve. Enhanced with permission resets, registry cleanup, manifest cache clearing, stuck session detection, and improved SSU automation for maximum effectiveness. .PARAMETER LogPath Path to the log file for detailed logging. .PARAMETER RepairSource Optional path to Windows installation media for offline repair source. .EXAMPLE $result = Resolve-WUComponentStore -LogPath "C:\Logs\wu.log" .NOTES This function requires Administrator privileges. Returns an object with Success, ActionsPerformed, and RebootRequired properties. Enhanced repair sequence with community best practices: 0. Advanced pre-repair cleanup (permissions, registry, caches) 1. DISM CheckHealth 2. DISM ScanHealth 3. DISM RestoreHealth (with automatic SSU on exit code 193) 4. SFC ScanNow 5. DISM Component Cleanup 6. Final health check #> param( [string]$LogPath = "$env:TEMP\WindowsUpdate.log", [string]$RepairSource = $null ) # Initialize result object $result = [PSCustomObject]@{ Success = $false CorruptionDetected = $false CorruptionRepaired = $false SevereError = $false StuckSessionsCleared = $false PermissionsReset = $false ManifestCacheCleared = $false RegistryRepaired = $false SSUInstalled = $false RebootRequired = $false ActionsPerformed = @() RepairDetails = @() DismCheckHealthExitCode = $null DismScanHealthExitCode = $null DismRestoreHealthExitCode = $null DismCleanupExitCode = $null ErrorMessage = $null } try { Write-WULog -Message "=== Windows Component Store Repair Started ===" -LogPath $LogPath Write-WULog -Message "PowerShell 5.1 compatible implementation with enhanced Exit Code 193 recovery" -LogPath $LogPath # Phase 0: Advanced Pre-Repair Cleanup Write-WULog -Message "Phase 0: Performing advanced pre-repair cleanup" -LogPath $LogPath # Clear stuck DISM sessions Write-WULog -Message "Clearing potentially stuck DISM sessions..." -LogPath $LogPath $stuckSessionsCleared = Clear-StuckDISMSessions -LogPath $LogPath if ($stuckSessionsCleared) { $result.StuckSessionsCleared = $true $result.ActionsPerformed += "Cleared stuck DISM sessions" } # Reset WinSxS and servicing folder permissions Write-WULog -Message "Resetting critical folder permissions..." -LogPath $LogPath $permissionsReset = Reset-ComponentStorePermissions -LogPath $LogPath if ($permissionsReset) { $result.PermissionsReset = $true $result.ActionsPerformed += "Reset component store permissions" } # Clear manifest cache Write-WULog -Message "Clearing manifest cache..." -LogPath $LogPath $manifestCacheCleared = Clear-ManifestCache -LogPath $LogPath if ($manifestCacheCleared) { $result.ManifestCacheCleared = $true $result.ActionsPerformed += "Cleared manifest cache" } # Clean CBS registry corruption Write-WULog -Message "Cleaning CBS registry corruption..." -LogPath $LogPath $registryRepaired = Repair-CBSRegistry -LogPath $LogPath if ($registryRepaired) { $result.RegistryRepaired = $true $result.ActionsPerformed += "Repaired CBS registry corruption" } # Enhanced service management with timeout handling Write-WULog -Message "Managing Windows Update services..." -LogPath $LogPath $services = @("wuauserv", "cryptsvc", "bits", "msiserver", "appidsvc", "trustedinstaller") foreach ($service in $services) { try { $svc = Get-Service -Name $service -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq "Running") { Write-WULog -Message "Stopping service: $service" -LogPath $LogPath # Try graceful stop first Stop-Service -Name $service -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 2 # Verify service stopped $svc = Get-Service -Name $service -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq "Running") { Write-WULog -Message "Forcefully stopping service: $service" -LogPath $LogPath $processes = Get-WmiObject -Class Win32_Service | Where-Object { $_.Name -eq $service } if ($processes) { $processes | ForEach-Object { try { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } catch { } } } } } } catch { Write-WULog -Message "Error managing service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } Start-Sleep -Seconds 5 # Phase 1: DISM CheckHealth Write-WULog -Message "Phase 1: Running DISM CheckHealth..." -LogPath $LogPath try { $checkHealthOutput = & dism.exe /online /cleanup-image /checkhealth 2>&1 $checkHealthExitCode = $LASTEXITCODE Write-WULog -Message "DISM CheckHealth exit code: $checkHealthExitCode" -LogPath $LogPath $result.DismCheckHealthExitCode = $checkHealthExitCode if ($checkHealthExitCode -eq 0) { Write-WULog -Message "DISM CheckHealth completed successfully" -LogPath $LogPath } else { Write-WULog -Message "DISM CheckHealth detected issues" -Level Warning -LogPath $LogPath $result.CorruptionDetected = $true } $result.ActionsPerformed += "DISM CheckHealth" } catch { Write-WULog -Message "Error during DISM CheckHealth: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Phase 2: DISM ScanHealth Write-WULog -Message "Phase 2: Running DISM ScanHealth..." -LogPath $LogPath try { $scanHealthOutput = & dism.exe /online /cleanup-image /scanhealth 2>&1 $scanHealthExitCode = $LASTEXITCODE Write-WULog -Message "DISM ScanHealth exit code: $scanHealthExitCode" -LogPath $LogPath $result.DismScanHealthExitCode = $scanHealthExitCode if ($scanHealthExitCode -eq 0) { Write-WULog -Message "DISM ScanHealth completed successfully" -LogPath $LogPath } else { Write-WULog -Message "DISM ScanHealth detected corruption" -Level Warning -LogPath $LogPath $result.CorruptionDetected = $true } $result.ActionsPerformed += "DISM ScanHealth" } catch { Write-WULog -Message "Error during DISM ScanHealth: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Phase 3: DISM RestoreHealth (with automatic SSU on exit code 193) Write-WULog -Message "Phase 3: Attempting component store repair..." -LogPath $LogPath try { $dismArgs = @("/online", "/cleanup-image", "/restorehealth") if ($RepairSource -and (Test-Path $RepairSource)) { $dismArgs += "/source:$RepairSource" $dismArgs += "/limitaccess" Write-WULog -Message "Using repair source: $RepairSource" -LogPath $LogPath } $restoreHealthOutput = & dism.exe $dismArgs 2>&1 $restoreHealthExitCode = $LASTEXITCODE Write-WULog -Message "DISM RestoreHealth exit code: $restoreHealthExitCode" -LogPath $LogPath $result.DismRestoreHealthExitCode = $restoreHealthExitCode if ($restoreHealthExitCode -eq 0) { Write-WULog -Message "DISM RestoreHealth completed successfully" -LogPath $LogPath $result.CorruptionRepaired = $true } elseif ($restoreHealthExitCode -eq 193) { $result.SevereError = $true Write-WULog -Message "SEVERE: DISM RestoreHealth exit code 193 - Attempting recovery strategies" -Level Error -LogPath $LogPath # Strategy 1: Try Windows installation media first $mediaRepairSuccess = $false try { Write-WULog -Message "Strategy 1: Attempting Windows installation media repair..." -LogPath $LogPath # First try to find existing ISO $isoLocations = @( "$env:USERPROFILE\Downloads\Win11_*_English_x64.iso", "$env:USERPROFILE\Downloads\*.iso", "C:\Temp\*.iso", "C:\Windows11\Win11_*_English_x64.iso", "D:\*.iso" ) $foundIso = $null foreach ($location in $isoLocations) { $isoFiles = Get-ChildItem -Path $location -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*Windows*11*" -or $_.Name -like "*Win11*" } | Sort-Object LastWriteTime -Descending if ($isoFiles) { $foundIso = $isoFiles[0].FullName Write-WULog -Message "Found existing Windows 11 ISO: $foundIso" -LogPath $LogPath break } } # If no ISO found, attempt automatic download if (-not $foundIso) { Write-WULog -Message "No Windows 11 ISO found locally. Attempting automatic download..." -Level Warning -LogPath $LogPath try { Write-WULog -Message "Starting automatic Windows 11 ISO download for Exit Code 193 recovery..." -LogPath $LogPath $isoResult = Get-WUWindows11ISO -OutputPath "$env:TEMP" -Force if ($isoResult -and $isoResult.Path -and (Test-Path $isoResult.Path)) { $foundIso = $isoResult.Path $isoSize = [math]::Round((Get-Item $foundIso).Length / 1GB, 2) Write-WULog -Message "Successfully downloaded Windows 11 ISO: $foundIso ($isoSize GB)" -LogPath $LogPath $result.ActionsPerformed += "Downloaded Windows 11 24H2 ISO automatically ($isoSize GB)" } else { Write-WULog -Message "Automatic ISO download failed - no valid ISO file returned" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Automatic ISO download failed: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } if ($foundIso) { Write-WULog -Message "Using Windows installation media: $foundIso" -LogPath $LogPath Write-WULog -Message "Mounting ISO and attempting DISM repair with installation source..." -LogPath $LogPath # Mount the ISO $mountResult = Mount-DiskImage -ImagePath $foundIso -PassThru $driveLetter = ($mountResult | Get-Volume).DriveLetter if ($driveLetter) { $sourcePath = "${driveLetter}:\sources\install.wim" if (Test-Path $sourcePath) { # Attempt repair with installation media Write-WULog -Message "Using installation source: $sourcePath" -LogPath $LogPath $dismMediaArgs = @("/online", "/cleanup-image", "/restorehealth", "/source:wim:${sourcePath}:1", "/limitaccess") $mediaRepairOutput = & dism.exe $dismMediaArgs 2>&1 $mediaRepairExitCode = $LASTEXITCODE Write-WULog -Message "DISM RestoreHealth with media exit code: $mediaRepairExitCode" -LogPath $LogPath if ($mediaRepairExitCode -eq 0) { Write-WULog -Message "SUCCESS: DISM RestoreHealth succeeded with Windows installation media!" -LogPath $LogPath $result.CorruptionRepaired = $true $result.SevereError = $false $result.ActionsPerformed += "DISM RestoreHealth with Windows media (primary strategy)" $result.DismRestoreHealthExitCode = $mediaRepairExitCode $mediaRepairSuccess = $true } else { Write-WULog -Message "DISM RestoreHealth with media failed (exit code: $mediaRepairExitCode)" -Level Error -LogPath $LogPath } } # Dismount the ISO Dismount-DiskImage -ImagePath $foundIso -ErrorAction SilentlyContinue } } else { Write-WULog -Message "No Windows installation media available - trying SSU strategy..." -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Error during Windows media repair attempt: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Strategy 2: Only try SSU if media repair failed or wasn't available if (-not $mediaRepairSuccess) { Write-WULog -Message "Strategy 2: Attempting SSU installation..." -LogPath $LogPath # Automatically attempt SSU installation try { Write-WULog -Message "Attempting automatic Servicing Stack Update installation..." -LogPath $LogPath $ssuResult = Install-WUServicingStackUpdate if ($ssuResult.Success) { $result.SSUInstalled = $true $result.ActionsPerformed += "Installed Servicing Stack Update" Write-WULog -Message "SSU installed successfully - retrying DISM RestoreHealth..." -LogPath $LogPath # Retry RestoreHealth after SSU $restoreHealthOutput = & dism.exe $dismArgs 2>&1 $restoreHealthExitCode = $LASTEXITCODE $result.DismRestoreHealthExitCode = $restoreHealthExitCode if ($restoreHealthExitCode -eq 0) { Write-WULog -Message "DISM RestoreHealth succeeded after SSU installation" -LogPath $LogPath $result.CorruptionRepaired = $true $result.SevereError = $false } else { Write-WULog -Message "DISM RestoreHealth still failed after SSU (exit code: $restoreHealthExitCode)" -Level Error -LogPath $LogPath } } else { Write-WULog -Message "SSU installation failed: $($ssuResult.Message)" -Level Error -LogPath $LogPath } } catch { Write-WULog -Message "Error during automatic SSU installation: $($_.Exception.Message)" -Level Error -LogPath $LogPath } } } else { Write-WULog -Message "DISM RestoreHealth failed with exit code: $restoreHealthExitCode" -Level Warning -LogPath $LogPath } $result.ActionsPerformed += "DISM RestoreHealth" } catch { Write-WULog -Message "Error during DISM RestoreHealth: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Phase 4: SFC ScanNow (after DISM RestoreHealth) Write-WULog -Message "Phase 4: Running System File Checker..." -LogPath $LogPath try { $sfcOutput = & sfc.exe /scannow 2>&1 $sfcExitCode = $LASTEXITCODE Write-WULog -Message "SFC exit code: $sfcExitCode" -LogPath $LogPath if ($sfcExitCode -eq 0) { Write-WULog -Message "SFC completed successfully" -LogPath $LogPath } else { Write-WULog -Message "SFC detected issues or failed" -Level Warning -LogPath $LogPath } $result.ActionsPerformed += "SFC ScanNow" } catch { Write-WULog -Message "Error during SFC: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Phase 5: DISM Component Cleanup Write-WULog -Message "Phase 5: Running DISM component cleanup..." -LogPath $LogPath try { $cleanupOutput = & dism.exe /online /cleanup-image /startcomponentcleanup /resetbase 2>&1 $cleanupExitCode = $LASTEXITCODE Write-WULog -Message "DISM cleanup exit code: $cleanupExitCode" -LogPath $LogPath $result.DismCleanupExitCode = $cleanupExitCode if ($cleanupExitCode -eq 0) { Write-WULog -Message "DISM component cleanup completed successfully" -LogPath $LogPath } else { Write-WULog -Message "DISM component cleanup encountered issues" -Level Warning -LogPath $LogPath } $result.ActionsPerformed += "DISM Component Cleanup" } catch { Write-WULog -Message "Error during DISM cleanup: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Phase 6: Final health check Write-WULog -Message "Phase 6: Final component store health check..." -LogPath $LogPath try { $finalCheckOutput = & dism.exe /online /cleanup-image /checkhealth 2>&1 $finalCheckExitCode = $LASTEXITCODE Write-WULog -Message "Final DISM CheckHealth exit code: $finalCheckExitCode" -LogPath $LogPath if ($finalCheckExitCode -eq 0) { Write-WULog -Message "Final health check: Component store is healthy" -LogPath $LogPath $result.Success = $true } else { Write-WULog -Message "Final health check: Component store still has issues" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Error during final health check: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Restart required services Write-WULog -Message "Restarting Windows Update services..." -LogPath $LogPath foreach ($service in $services) { try { $svc = Get-Service -Name $service -ErrorAction SilentlyContinue if ($svc -and $svc.Status -eq "Stopped") { Write-WULog -Message "Starting service: $service" -LogPath $LogPath Start-Service -Name $service -ErrorAction SilentlyContinue } } catch { Write-WULog -Message "Error starting service $service`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Set reboot requirement if ($result.Success -or $result.CorruptionDetected -or $result.SSUInstalled) { $result.RebootRequired = $true Write-WULog -Message "RECOMMENDATION: Restart the system to complete component store repair" -Level Warning -LogPath $LogPath } } catch { $result.ErrorMessage = $_.Exception.Message $result.Success = $false Write-WULog -Message "Critical error during component store repair: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Summary reporting Write-WULog -Message "=== Component Store Repair Summary ===" -LogPath $LogPath Write-WULog -Message "Success: $($result.Success)" -LogPath $LogPath Write-WULog -Message "Corruption Detected: $($result.CorruptionDetected)" -LogPath $LogPath Write-WULog -Message "Severe Errors: $($result.SevereError)" -LogPath $LogPath Write-WULog -Message "SSU Installed: $($result.SSUInstalled)" -LogPath $LogPath Write-WULog -Message "Reboot Required: $($result.RebootRequired)" -LogPath $LogPath if ($result.ActionsPerformed.Count -gt 0) { Write-WULog -Message "Actions Performed:" -LogPath $LogPath foreach ($action in $result.ActionsPerformed) { Write-WULog -Message " - $action" -LogPath $LogPath } } if ($result.SevereError) { Write-WULog -Message "=== SEVERE ERROR RECOVERY GUIDANCE ===" -Level Error -LogPath $LogPath Write-WULog -Message "Component store corruption requires manual intervention:" -Level Error -LogPath $LogPath Write-WULog -Message "1. Download Windows 11 24H2 ISO from Microsoft" -Level Error -LogPath $LogPath Write-WULog -Message "2. Place in Downloads folder as Win11_*_English_x64.iso" -Level Error -LogPath $LogPath Write-WULog -Message "3. Run: dism /online /cleanup-image /restorehealth /source:wim:D:\sources\install.wim:1 /limitaccess" -Level Error -LogPath $LogPath Write-WULog -Message "4. Alternatively, consider in-place upgrade or reset" -Level Error -LogPath $LogPath } return $result } # Helper function to clear stuck DISM sessions function Clear-StuckDISMSessions { param([string]$LogPath) try { Write-WULog -Message "Checking for stuck DISM sessions..." -LogPath $LogPath # Check for running DISM processes $dismProcesses = Get-Process -Name "dism" -ErrorAction SilentlyContinue if ($dismProcesses) { Write-WULog -Message "Found $($dismProcesses.Count) running DISM process(es), terminating..." -LogPath $LogPath $dismProcesses | Stop-Process -Force -ErrorAction SilentlyContinue Start-Sleep -Seconds 3 } # Clear DISM session registry $dismSessionPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\SessionsPending" if (Test-Path $dismSessionPath) { Write-WULog -Message "Clearing DISM session registry..." -LogPath $LogPath Remove-Item -Path $dismSessionPath -Recurse -Force -ErrorAction SilentlyContinue } # Clear DISM mount points try { $mountOutput = & dism.exe /cleanup-mountpoints 2>&1 Write-WULog -Message "DISM cleanup mountpoints: $($mountOutput -join ' ')" -LogPath $LogPath } catch { Write-WULog -Message "Could not cleanup DISM mountpoints: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } return $true } catch { Write-WULog -Message "Error clearing stuck DISM sessions: $($_.Exception.Message)" -Level Warning -LogPath $LogPath return $false } } # Helper function to reset component store permissions function Reset-ComponentStorePermissions { param([string]$LogPath) try { Write-WULog -Message "Resetting component store folder permissions..." -LogPath $LogPath # Critical folders that need proper permissions $criticalFolders = @( "$env:windir\WinSxS", "$env:windir\servicing", "$env:windir\System32\catroot2", "$env:windir\SoftwareDistribution" ) foreach ($folder in $criticalFolders) { if (Test-Path $folder) { try { Write-WULog -Message "Resetting permissions for: $folder" -LogPath $LogPath & icacls.exe $folder /reset /t /c /q 2>&1 | Out-Null & icacls.exe $folder /grant "NT AUTHORITY\SYSTEM:(OI)(CI)F" /t /c /q 2>&1 | Out-Null & icacls.exe $folder /grant "BUILTIN\Administrators:(OI)(CI)F" /t /c /q 2>&1 | Out-Null } catch { Write-WULog -Message "Could not reset permissions for $folder`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } return $true } catch { Write-WULog -Message "Error resetting component store permissions: $($_.Exception.Message)" -Level Warning -LogPath $LogPath return $false } } # Helper function to clear manifest cache function Clear-ManifestCache { param([string]$LogPath) try { Write-WULog -Message "Clearing Windows manifest cache..." -LogPath $LogPath # Clear manifest cache registry $manifestCachePaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackageIndex", "HKLM:\COMPONENTS" ) foreach ($path in $manifestCachePaths) { if (Test-Path $path) { try { Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "Cleared manifest cache: $path" -LogPath $LogPath } catch { } } } # Clear file-based caches $manifestFiles = @( "$env:windir\servicing\Packages\*", "$env:windir\WinSxS\ManifestCache\*" ) foreach ($filePattern in $manifestFiles) { try { Get-ChildItem -Path $filePattern -ErrorAction SilentlyContinue | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue } catch { } } return $true } catch { Write-WULog -Message "Error clearing manifest cache: $($_.Exception.Message)" -Level Warning -LogPath $LogPath return $false } } # Helper function to repair CBS registry corruption function Repair-CBSRegistry { param([string]$LogPath) try { Write-WULog -Message "Repairing CBS registry corruption..." -LogPath $LogPath # Clear problematic CBS registry entries $cbsPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackageDetect", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\SessionsPending", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" ) foreach ($path in $cbsPaths) { if (Test-Path $path) { try { Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "Cleared CBS registry path: $path" -LogPath $LogPath } catch { Write-WULog -Message "Could not clear CBS registry path $path`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } # Clear pending package operations $pendingPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages", "HKLM:\COMPONENTS\PendingXmlIdentifier", "HKLM:\COMPONENTS\NextQueueEntryIndex" ) foreach ($path in $pendingPaths) { if (Test-Path $path) { try { Remove-Item -Path $path -Recurse -Force -ErrorAction SilentlyContinue Write-WULog -Message "Cleared registry path: $path" -LogPath $LogPath } catch { Write-WULog -Message "Could not clear registry path $path`: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } } return $true } catch { Write-WULog -Message "Error repairing CBS registry: $($_.Exception.Message)" -Level Warning -LogPath $LogPath return $false } } |