dist/temp/WindowsUpdateTools/Private/Test-WUComponentStore.ps1
|
function Test-WUComponentStore { <# .SYNOPSIS Tests Windows Component Store health for corruption issues. .DESCRIPTION Performs component store health assessment using DISM CheckHealth and ScanHealth operations. Also analyzes CBS.log for corruption indicators. .PARAMETER LogPath Path to the log file for detailed logging. .EXAMPLE $componentHealth = Test-WUComponentStore -LogPath "C:\Logs\wu.log" .NOTES This is a private function used internally by the WindowsUpdateTools module. Returns component store health status and corruption indicators. #> [CmdletBinding()] param( [string]$LogPath ) Write-WULog -Message "Testing Component Store health" -LogPath $LogPath # Initialize results object $results = [PSCustomObject]@{ CorruptionDetected = $false HealthCheckPassed = $false ScanHealthPassed = $false CBSLogIssues = 0 CBSLogIndicators = @() Issues = @() CheckHealthExitCode = $null ScanHealthExitCode = $null ErrorMessage = $null } try { # Step 1: DISM CheckHealth (quick check) Write-WULog -Message "Running DISM CheckHealth..." -LogPath $LogPath try { $checkHealthOutput = & dism.exe /online /cleanup-image /checkhealth 2>&1 $results.CheckHealthExitCode = $LASTEXITCODE Write-WULog -Message "DISM CheckHealth exit code: $($results.CheckHealthExitCode)" -LogPath $LogPath if ($results.CheckHealthExitCode -eq 0) { if ($checkHealthOutput -like "*Component Store is repairable*") { $results.CorruptionDetected = $true $results.Issues += "DISM CheckHealth detected repairable component store corruption" Write-WULog -Message "Component store corruption detected by CheckHealth" -Level Warning -LogPath $LogPath } else { $results.HealthCheckPassed = $true Write-WULog -Message "DISM CheckHealth passed - no corruption detected" -LogPath $LogPath } } else { $results.Issues += "DISM CheckHealth failed with exit code: $($results.CheckHealthExitCode)" Write-WULog -Message "DISM CheckHealth failed with exit code: $($results.CheckHealthExitCode)" -Level Warning -LogPath $LogPath } } catch { $results.Issues += "Error running DISM CheckHealth: $($_.Exception.Message)" Write-WULog -Message "Error running DISM CheckHealth: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Step 2: DISM ScanHealth (more thorough check) - only if CheckHealth passed or we want to be thorough if ($results.HealthCheckPassed -or $results.CorruptionDetected) { Write-WULog -Message "Running DISM ScanHealth for thorough analysis..." -LogPath $LogPath try { $scanHealthOutput = & dism.exe /online /cleanup-image /scanhealth 2>&1 $results.ScanHealthExitCode = $LASTEXITCODE Write-WULog -Message "DISM ScanHealth exit code: $($results.ScanHealthExitCode)" -LogPath $LogPath if ($results.ScanHealthExitCode -eq 0) { if ($scanHealthOutput -like "*Component Store corruption was detected*") { $results.CorruptionDetected = $true $results.Issues += "DISM ScanHealth confirmed component store corruption" Write-WULog -Message "Component store corruption confirmed by ScanHealth" -Level Warning -LogPath $LogPath } else { $results.ScanHealthPassed = $true Write-WULog -Message "DISM ScanHealth passed - no corruption detected" -LogPath $LogPath } } else { $results.Issues += "DISM ScanHealth failed with exit code: $($results.ScanHealthExitCode)" Write-WULog -Message "DISM ScanHealth failed with exit code: $($results.ScanHealthExitCode)" -Level Warning -LogPath $LogPath } } catch { $results.Issues += "Error running DISM ScanHealth: $($_.Exception.Message)" Write-WULog -Message "Error running DISM ScanHealth: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } } # Step 3: Analyze CBS.log for corruption indicators Write-WULog -Message "Analyzing CBS.log for corruption indicators..." -LogPath $LogPath try { $cbsLogPath = "$env:WINDIR\Logs\CBS\CBS.log" if (Test-Path $cbsLogPath) { # Get recent entries (last 500 lines for better coverage of detailed errors) $recentCbsEntries = Get-Content $cbsLogPath -Tail 500 -ErrorAction SilentlyContinue if ($recentCbsEntries) { $corruptionIndicators = @() foreach ($line in $recentCbsEntries) { $lineLower = $line.ToLower() # Skip normal operational messages and zero-corruption summary lines if ($lineLower -like "*corruption detection*" -or $lineLower -like "*storecorruptionrepair transaction*" -or $lineLower -like "*numcorruptions = 0*" -or $lineLower -like "*starting corruption detection*" -or $lineLower -like "*corruption: 0*" -or $lineLower -like "*corruption: 0*" -or $lineLower -like "*corruption complete*" -or $lineLower -like "*corruption detected: 0*" -or $lineLower -like "*times corruption detected: 0*" -or $lineLower -like "*successfully*" -or $lineLower -like "*completed successfully*" -or $lineLower -like "*operation completed*" -or $lineLower -like "*manifest corruption:*0*" -or # CBS/CSI Manifest Corruption: 0 $lineLower -like "*csi manifest corruption:*0*" -or # CSI Manifest Corruption: 0 $lineLower -like "*cbs manifest corruption:*0*" -or # CBS Manifest Corruption: 0 $lineLower -like "*corruption:*0*" -or # Any corruption count showing 0 $lineLower -like "*corruption*:*0*" -or # Any corruption field showing 0 $lineLower -like "*corruption detected*0*" -or # Any corruption detected showing 0 $lineLower -like "*times*corruption*0*") { # Any times corruption showing 0 continue } # Look for actual corruption/error indicators - both summary counts and specific details $isCorruptionIndicator = $false # Summary patterns (non-zero corruption counts) - use regex for precise matching if ($lineLower -match "corruption detected:\s*[1-9]\d*" -or $lineLower -match "times corruption detected:\s*[1-9]\d*" -or $lineLower -match "numcorruptions\s*=\s*[1-9]\d*" -or ($lineLower -match "corruption:\s*[1-9]\d*" -and $lineLower -notlike "*manifest corruption:*")) { $isCorruptionIndicator = $true } # Specific corruption detail patterns - exclude summary/informational lines $detailPatterns = @( '*failed to resolve component*', # Component resolution failures '*component identity*failed*', # Component identity issues '*manifest file is corrupt*', # Direct manifest corruption '*payload file is corrupt*', # Direct payload corruption '*cannot repair*', # Repair failures '*failed to repair*', # Repair failures '*repair failed*', # Repair failures '*corruption*cannot*repair*', # Unrepairable corruption '*hash mismatch*', # File integrity issues '*checksum*mismatch*', # File integrity issues '*invalid*manifest*', # Invalid manifest files '*component*missing*', # Missing components '*missing*component*', # Missing components '*error 0x8007*', # Common corruption error codes '*error 0x800f*', # CBS-specific error codes '*hresult 0x8*', # HRESULT corruption errors '*component store corruption was detected*', # Actual detection messages '*servicing corruption*', # Servicing corruption '*catalog*corrupt*', # Catalog corruption '*corrupt*catalog*', # Catalog corruption '*identity*corrupt*', # Identity corruption '*corrupt*identity*' # Identity corruption ) # Only check detail patterns if not already flagged and avoid generic corruption mentions if (-not $isCorruptionIndicator) { foreach ($pattern in $detailPatterns) { if ($lineLower -like $pattern -and $lineLower -notlike "*manifest corruption:*" -and $lineLower -notlike "*csi manifest corruption:*" -and $lineLower -notlike "*cbs manifest corruption:*") { $isCorruptionIndicator = $true break } } } if ($isCorruptionIndicator) { $corruptionIndicators += $line.Trim() } } $results.CBSLogIssues = $corruptionIndicators.Count $results.CBSLogIndicators = $corruptionIndicators if ($corruptionIndicators.Count -gt 0) { $results.Issues += "Found $($corruptionIndicators.Count) potential corruption indicators in CBS.log" Write-WULog -Message "Found $($corruptionIndicators.Count) potential corruption indicators in CBS.log" -Level Warning -LogPath $LogPath # Log a summary with limited details to avoid excessive output if ($corruptionIndicators.Count -le 3) { # If few indicators, log them all Write-WULog -Message "CBS Log Corruption Details:" -Level Warning -LogPath $LogPath foreach ($indicator in $corruptionIndicators) { Write-WULog -Message " $indicator" -LogPath $LogPath } } else { # If many indicators, just show first 2 and provide summary $sampleIndicators = $corruptionIndicators | Select-Object -First 2 Write-WULog -Message "CBS Log Corruption Sample (first 2 of $($corruptionIndicators.Count)):" -Level Warning -LogPath $LogPath foreach ($indicator in $sampleIndicators) { Write-WULog -Message " $indicator" -LogPath $LogPath } Write-WULog -Message " ... and $($corruptionIndicators.Count - 2) more indicators (see full list in CBSLogIndicators property)" -LogPath $LogPath } # If we have any actual indicators, this suggests corruption $results.CorruptionDetected = $true Write-WULog -Message "Actual corruption indicators found in CBS.log" -Level Warning -LogPath $LogPath } else { Write-WULog -Message "No corruption indicators found in recent CBS.log entries" -LogPath $LogPath } } else { $results.Issues += "Could not read CBS.log entries" Write-WULog -Message "Could not read CBS.log entries" -Level Warning -LogPath $LogPath } } else { $results.Issues += "CBS.log not found at expected location" Write-WULog -Message "CBS.log not found at $cbsLogPath" -Level Warning -LogPath $LogPath } } catch { $results.Issues += "Error analyzing CBS.log: $($_.Exception.Message)" Write-WULog -Message "Error analyzing CBS.log: $($_.Exception.Message)" -Level Warning -LogPath $LogPath } # Step 4: Check for pending component store operations try { $pendingOperations = Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" if ($pendingOperations) { $results.Issues += "Pending component store operations detected - reboot may be required" Write-WULog -Message "Pending component store operations detected" -Level Warning -LogPath $LogPath } } catch { Write-WULog -Message "Could not check for pending component store operations" -Level Warning -LogPath $LogPath } } catch { $results.ErrorMessage = $_.Exception.Message Write-WULog -Message "Critical error during component store health test: $($_.Exception.Message)" -Level Error -LogPath $LogPath } # Summary Write-WULog -Message "Component Store health test completed:" -LogPath $LogPath Write-WULog -Message " Corruption detected: $($results.CorruptionDetected)" -LogPath $LogPath Write-WULog -Message " Health check passed: $($results.HealthCheckPassed)" -LogPath $LogPath Write-WULog -Message " Scan health passed: $($results.ScanHealthPassed)" -LogPath $LogPath Write-WULog -Message " CBS log issues: $($results.CBSLogIssues)" -LogPath $LogPath Write-WULog -Message " Total issues found: $($results.Issues.Count)" -LogPath $LogPath if ($results.CorruptionDetected) { Write-WULog -Message "RECOMMENDATION: Run component store repair (DISM RestoreHealth)" -Level Warning -LogPath $LogPath } return $results } |