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
}