Private/Invoke-InfraPulseCpuCheck.ps1

function Invoke-InfraPulseCpuCheck {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [psobject]$Context,

        [Parameter(Mandatory)]
        [System.Collections.IDictionary]$Settings
    )

    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    $scriptBlock = {
        param($CheckSettings)

        if ($env:OS -ne 'Windows_NT') {
            throw 'The Cpu check requires a Windows target.'
        }

        $useCim = [bool](Get-Command -Name Get-CimInstance -ErrorAction SilentlyContinue)
        $samples = New-Object System.Collections.Generic.List[double]

        # A single reading is a coin flip on a busy host; a short averaged
        # series separates sustained pressure from momentary spikes.
        for ($sampleIndex = 1; $sampleIndex -le [int]$CheckSettings.SampleCount; $sampleIndex++) {
            $processors = if ($useCim) {
                @(Get-CimInstance -ClassName Win32_Processor -ErrorAction Stop)
            }
            else {
                @(Get-WmiObject -Class Win32_Processor -ErrorAction Stop)
            }

            $loadValues = @(
                foreach ($processor in $processors) {
                    $loadProperty = $processor.PSObject.Properties['LoadPercentage']
                    if ($null -ne $loadProperty -and $null -ne $loadProperty.Value) {
                        [double]$loadProperty.Value
                    }
                }
            )
            if ($loadValues.Count -gt 0) {
                [void]$samples.Add(($loadValues | Measure-Object -Average).Average)
            }

            if ($sampleIndex -lt [int]$CheckSettings.SampleCount) {
                Start-Sleep -Seconds ([int]$CheckSettings.SampleIntervalSeconds)
            }
        }

        $logicalProcessors = $null
        try {
            $computerSystem = if ($useCim) {
                Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
            }
            else {
                Get-WmiObject -Class Win32_ComputerSystem -ErrorAction Stop
            }
            $logicalProcessors = [int]$computerSystem.NumberOfLogicalProcessors
        }
        catch {
            $logicalProcessors = $null
        }

        $topProcesses = @(
            Get-Process -ErrorAction SilentlyContinue |
                Sort-Object -Property WorkingSet64 -Descending |
                Select-Object -First 5 |
                ForEach-Object {
                    [pscustomobject]@{
                        Name         = [string]$_.ProcessName
                        Id           = [int]$_.Id
                        WorkingSetMB = [math]::Round([double]$_.WorkingSet64 / 1MB, 1)
                    }
                }
        )

        [pscustomobject]@{
            Samples           = @($samples.ToArray())
            LogicalProcessors = $logicalProcessors
            TopProcesses      = $topProcesses
        }
    }

    $cpuState = Invoke-InfraPulseCommand -Context $Context -ScriptBlock $scriptBlock -ArgumentList @($Settings)
    $stopwatch.Stop()

    $samples = @($cpuState.Samples | ForEach-Object { [math]::Round([double]$_, 1) })
    if ($samples.Count -eq 0) {
        return New-InfraPulseResult -Status 'Unknown' -CheckName 'Cpu' -Category 'Capacity' -ComputerName $Context.ComputerName -Target 'Processor' -Message 'No processor load samples could be collected.' -Recommendation 'Validate Win32_Processor access on the target; LoadPercentage returned no values.' -DurationMs $stopwatch.Elapsed.TotalMilliseconds
    }

    $averagePercent = [math]::Round((@($samples) | Measure-Object -Average).Average, 1)

    if ($averagePercent -ge [double]$Settings.CriticalPercent) {
        $status = 'Critical'
        $recommendation = 'Identify the drivers of the sustained load and rebalance, scale, or schedule the workload before it starves other services.'
    }
    elseif ($averagePercent -ge [double]$Settings.WarningPercent) {
        $status = 'Warning'
        $recommendation = 'Review the top processes and workload placement; sustained load at this level leaves little headroom.'
    }
    else {
        $status = 'Healthy'
        $recommendation = ''
    }

    $message = "Average CPU load $averagePercent% across $($samples.Count) sample(s)."
    $evidence = [ordered]@{
        AveragePercent    = $averagePercent
        Samples           = $samples
        SampleCount       = $samples.Count
        LogicalProcessors = $cpuState.LogicalProcessors
        TopProcesses      = @($cpuState.TopProcesses)
    }

    return New-InfraPulseResult -Status $status -CheckName 'Cpu' -Category 'Capacity' -ComputerName $Context.ComputerName -Target 'Processor' -Message $message -ObservedValue ("{0:N1}%" -f $averagePercent) -WarningThreshold (">= {0}%" -f $Settings.WarningPercent) -CriticalThreshold (">= {0}%" -f $Settings.CriticalPercent) -Recommendation $recommendation -Evidence $evidence -DurationMs $stopwatch.Elapsed.TotalMilliseconds
}