Private/Get-WUSystemHealth.ps1

function Get-WUSystemHealth {
    <#
    .SYNOPSIS
        Performs comprehensive Windows Update system health assessment.
 
    .DESCRIPTION
        Comprehensive health check based on the original ResolveUpdateFailures.ps1 logic.
        Checks services, pending updates, event logs, component store, and configuration
        to determine if remediation is needed when no specific issues are detected.
 
    .PARAMETER LogPath
        Path to the log file for detailed logging.
 
    .EXAMPLE
        $health = Get-WUSystemHealth -LogPath "C:\Logs\wu.log"
 
    .NOTES
        This is a private function used internally by the WindowsUpdateTools module.
        Ported from the original Test-SystemHealthIndicators function.
        Returns comprehensive health status and specific issue indicators.
    #>


    [CmdletBinding()]
    param(
        [string]$LogPath
    )

Write-WULog -Message "Performing comprehensive Windows Update system health assessment" -LogPath $LogPath

# Initialize health result
$healthResult = [PSCustomObject]@{
    Healthy = $true
    ComponentStoreCorruption = $false
    ServiceIssues = $false
    DiskSpaceIssues = $false
    RecentErrors = $false
    ConfigurationIssues = $false
    PendingUpdatesIssues = $false
    Issues = @()
    Summary = ""
}

try {
    # Check Windows Update service status (from original script logic)
    Write-WULog -Message "Checking Windows Update service status..." -LogPath $LogPath
    try {
        $wuService = Get-Service -Name "wuauserv" -ErrorAction Stop
        if ($wuService.Status -ne "Running") {
            $healthResult.ServiceIssues = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Windows Update service not running ($($wuService.Status))"
        }
    }
    catch {
        $healthResult.ServiceIssues = $true
        $healthResult.Healthy = $false
        $healthResult.Issues += "Windows Update service not found or accessible"
    }
    
    # Check BITS service status
    try {
        $bitsService = Get-Service -Name "BITS" -ErrorAction Stop
        if ($bitsService.Status -ne "Running") {
            $healthResult.ServiceIssues = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "BITS service not running ($($bitsService.Status))"
        }
    }
    catch {
        $healthResult.ServiceIssues = $true
        $healthResult.Healthy = $false
        $healthResult.Issues += "BITS service not found or accessible"
    }

    # Check cryptographic services
    try {
        $cryptSvc = Get-Service -Name "cryptsvc" -ErrorAction Stop
        if ($cryptSvc.Status -ne "Running") {
            $healthResult.ServiceIssues = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Cryptographic Services not running"
        }
    }
    catch {
        $healthResult.ServiceIssues = $true
        $healthResult.Healthy = $false
        $healthResult.Issues += "Cryptographic Services not accessible"
    }

    # Check for pending updates (from original script)
    Write-WULog -Message "Checking for pending updates..." -LogPath $LogPath
    try {
        $updateSession = New-Object -ComObject Microsoft.Update.Session
        $updateSearcher = $updateSession.CreateUpdateSearcher()
        $searchResult = $updateSearcher.Search("IsInstalled=0")
        if ($searchResult.Updates.Count -gt 0) {
            $healthResult.Issues += "Found $($searchResult.Updates.Count) pending updates"
            Write-WULog -Message "Found $($searchResult.Updates.Count) pending updates" -LogPath $LogPath
            
            # Check for very old pending updates (might indicate stuck updates)
            $oldUpdates = 0
            foreach ($update in $searchResult.Updates) {
                if ($update.LastDeploymentChangeTime -and (Get-Date) - $update.LastDeploymentChangeTime -gt [TimeSpan]::FromDays(30)) {
                    $oldUpdates++
                }
            }
            if ($oldUpdates -gt 0) {
                $healthResult.PendingUpdatesIssues = $true
                $healthResult.Issues += "$oldUpdates pending updates are over 30 days old"
            }
        }
    }
    catch {
        $healthResult.Issues += "Could not check for pending updates"
        Write-WULog -Message "Could not check for pending updates: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Check for recent Windows Update errors (from original logic)
    Write-WULog -Message "Checking for recent Windows Update errors..." -LogPath $LogPath
    try {
        $recentErrors = Get-WinEvent -FilterHashtable @{
            LogName = @('System', 'Application', 'Microsoft-Windows-WindowsUpdateClient/Operational')
            Level = 1..2  # Critical and Error only
            StartTime = (Get-Date).AddDays(-3)
        } -MaxEvents 50 -ErrorAction SilentlyContinue | Where-Object {
            $_.LevelDisplayName -eq "Error" -and
            ($_.Message -like "*update*" -or $_.Message -like "*0x8*" -or $_.ProviderName -like "*Update*")
        }
        
        if ($recentErrors) {
            $healthResult.RecentErrors = $true
            $healthResult.Issues += "Found $($recentErrors.Count) recent update-related errors in event logs"
            
            if ($recentErrors.Count -gt 10) {
                $healthResult.Healthy = $false
            }
        }
    }
    catch {
        Write-WULog -Message "Could not check recent update errors: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Check component store health (enhanced from original)
    Write-WULog -Message "Checking component store health..." -LogPath $LogPath
    try {
        $dismOutput = & dism.exe /online /cleanup-image /checkhealth 2>&1
        $dismExitCode = $LASTEXITCODE
        
        if ($dismExitCode -ne 0) {
            $healthResult.ComponentStoreCorruption = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Component store health check failed (Exit code: $dismExitCode)"
        }
        elseif ($dismOutput -like "*Component Store is repairable*") {
            $healthResult.ComponentStoreCorruption = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Component store corruption detected"
        }
    }
    catch {
        Write-WULog -Message "Could not check component store health: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Check disk space (from original script logic)
    Write-WULog -Message "Checking system disk space..." -LogPath $LogPath
    try {
        $systemDrive = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $env:SystemDrive }
        $freeSpaceGB = [math]::Round($systemDrive.FreeSpace / 1GB, 2)
        
        if ($freeSpaceGB -lt 5) {
            $healthResult.DiskSpaceIssues = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Critical disk space - only $freeSpaceGB GB free"
        } elseif ($freeSpaceGB -lt 10) {
            $healthResult.DiskSpaceIssues = $true
            $healthResult.Issues += "Low disk space - $freeSpaceGB GB free"
        }
    }
    catch {
        Write-WULog -Message "Could not check disk space: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Check Windows Update configuration (from original)
    Write-WULog -Message "Checking Windows Update configuration..." -LogPath $LogPath
    try {
        # Check if Windows Update service is disabled
        $wuServiceConfig = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv" -ErrorAction SilentlyContinue
        if ($wuServiceConfig -and $wuServiceConfig.Start -eq 4) {  # 4 = Disabled
            $healthResult.ConfigurationIssues = $true
            $healthResult.Healthy = $false
            $healthResult.Issues += "Windows Update service is disabled at the system level"
        }

        # Check if automatic updates are disabled via policy
        $auDisabled = Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "NoAutoUpdate" -ErrorAction SilentlyContinue
        if ($auDisabled -and $auDisabled.NoAutoUpdate -eq 1) {
            $healthResult.ConfigurationIssues = $true
            $healthResult.Issues += "Automatic updates are disabled via Group Policy"
        }
    }
    catch {
        Write-WULog -Message "Could not check Windows Update configuration: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Check for pending reboot (from original script logic)
    try {
        $pendingReboot = $false
        
        # Windows Update pending reboot
        if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") {
            $pendingReboot = $true
        }
        
        # Component Based Servicing pending reboot
        if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") {
            $pendingReboot = $true
        }
        
        # Pending file rename operations
        $pendingFileRenames = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name "PendingFileRenameOperations" -ErrorAction SilentlyContinue
        if ($pendingFileRenames) {
            $pendingReboot = $true
        }
        
        if ($pendingReboot) {
            $healthResult.Issues += "Pending reboot detected - may affect Windows Update operations"
            Write-WULog -Message "Pending reboot detected" -Level Warning -LogPath $LogPath
        }
    }
    catch {
        Write-WULog -Message "Could not check pending reboot status: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
    }

    # Generate summary (simple, no scoring nonsense)
    if ($healthResult.Healthy) {
        $healthResult.Summary = "System is healthy for Windows Update operations"
        Write-WULog -Message "System health assessment: HEALTHY" -LogPath $LogPath
    } else {
        $issueCount = $healthResult.Issues.Count
        $healthResult.Summary = "System health issues detected ($issueCount issues found)"
        Write-WULog -Message "System health assessment: ISSUES DETECTED ($issueCount issues)" -Level Warning -LogPath $LogPath
    }

    # Log specific issue areas (from original categorization)
    $issueAreas = @()
    if ($healthResult.ServiceIssues) { $issueAreas += "Services" }
    if ($healthResult.ComponentStoreCorruption) { $issueAreas += "Component Store" }
    if ($healthResult.DiskSpaceIssues) { $issueAreas += "Disk Space" }
    if ($healthResult.RecentErrors) { $issueAreas += "Recent Errors" }
    if ($healthResult.ConfigurationIssues) { $issueAreas += "Configuration" }
    if ($healthResult.PendingUpdatesIssues) { $issueAreas += "Pending Updates" }

    if ($issueAreas.Count -gt 0) {
        Write-WULog -Message "Issue areas identified: $($issueAreas -join ', ')" -LogPath $LogPath
    }

    if ($healthResult.Issues.Count -gt 0) {
        Write-WULog -Message "Specific issues found:" -LogPath $LogPath
        foreach ($issue in $healthResult.Issues) {
            Write-WULog -Message " - $issue" -LogPath $LogPath
        }
    }
}
catch {    $healthResult.Healthy = $false
    $healthResult.Issues += "Error during health assessment: $($_.Exception.Message)"
    $healthResult.Summary = "Health assessment failed"
    Write-WULog -Message "Error during system health assessment: $($_.Exception.Message)" -Level Error -LogPath $LogPath
}

return $healthResult
}
return $healthResult