Private/Invoke-InfraPulseStorageCheck.ps1

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

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

    # The Storage check has no tunable settings beyond Enabled; the parameter keeps the shared check signature.
    $null = $Settings

    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    $scriptBlock = {
        if ($env:OS -ne 'Windows_NT') {
            throw 'The Storage check requires a Windows target.'
        }

        if (-not (Get-Command -Name Get-PhysicalDisk -ErrorAction SilentlyContinue) -or -not (Get-Command -Name Get-Volume -ErrorAction SilentlyContinue)) {
            return [pscustomobject]@{
                Supported = $false
                Disks     = @()
                Volumes   = @()
            }
        }

        $disks = @(
            Get-PhysicalDisk -ErrorAction Stop | ForEach-Object {
                [pscustomobject]@{
                    FriendlyName      = [string]$_.FriendlyName
                    MediaType         = [string]$_.MediaType
                    HealthStatus      = [string]$_.HealthStatus
                    OperationalStatus = (@($_.OperationalStatus) -join ', ')
                    SizeGB            = [math]::Round([double]$_.Size / 1GB, 2)
                }
            }
        )

        $volumes = @(
            Get-Volume -ErrorAction Stop |
                Where-Object { [string]$_.DriveType -eq 'Fixed' } |
                ForEach-Object {
                    [pscustomobject]@{
                        DriveLetter     = [string]$_.DriveLetter
                        FileSystemLabel = [string]$_.FileSystemLabel
                        FileSystem      = [string]$_.FileSystem
                        HealthStatus    = [string]$_.HealthStatus
                    }
                }
        )

        [pscustomobject]@{
            Supported = $true
            Disks     = $disks
            Volumes   = $volumes
        }
    }

    $storage = Invoke-InfraPulseCommand -Context $Context -ScriptBlock $scriptBlock
    $stopwatch.Stop()

    if (-not [bool]$storage.Supported) {
        return New-InfraPulseResult -Status 'Unknown' -CheckName 'Storage' -Category 'Reliability' -ComputerName $Context.ComputerName -Target 'Storage health' -Message 'Storage health interfaces are unavailable on the target.' -Recommendation 'Get-PhysicalDisk and Get-Volume require the Storage module (Windows Server 2012 / Windows 8 or later).' -DurationMs $stopwatch.Elapsed.TotalMilliseconds
    }

    $disks = @($storage.Disks)
    $volumes = @($storage.Volumes)
    $results = @()
    $unhealthyCount = 0

    foreach ($disk in $disks) {
        $healthStatus = [string]$disk.HealthStatus
        if ($healthStatus -eq 'Healthy' -or [string]::IsNullOrWhiteSpace($healthStatus)) {
            continue
        }
        $unhealthyCount++
        $status = if ($healthStatus -eq 'Warning') { 'Warning' } else { 'Critical' }
        $evidence = [ordered]@{
            FriendlyName      = [string]$disk.FriendlyName
            MediaType         = [string]$disk.MediaType
            HealthStatus      = $healthStatus
            OperationalStatus = [string]$disk.OperationalStatus
            SizeGB            = $disk.SizeGB
        }
        $results += New-InfraPulseResult -Status $status -CheckName 'Storage' -Category 'Reliability' -ComputerName $Context.ComputerName -Target ([string]$disk.FriendlyName) -Message "Physical disk '$($disk.FriendlyName)' reports health status '$healthStatus' ($($disk.OperationalStatus))." -ObservedValue $healthStatus -CriticalThreshold 'Health status must be Healthy' -Recommendation 'Check hardware diagnostics, controller state, and vendor tooling; plan a replacement before the disk fails.' -Evidence $evidence -DurationMs ($stopwatch.Elapsed.TotalMilliseconds / [math]::Max($disks.Count + $volumes.Count, 1))
    }

    foreach ($volume in $volumes) {
        $healthStatus = [string]$volume.HealthStatus
        if ($healthStatus -eq 'Healthy' -or [string]::IsNullOrWhiteSpace($healthStatus)) {
            continue
        }
        $unhealthyCount++
        $status = if ($healthStatus -eq 'Warning') { 'Warning' } else { 'Critical' }
        $volumeLabel = if ([string]::IsNullOrWhiteSpace([string]$volume.DriveLetter)) { [string]$volume.FileSystemLabel } else { "$($volume.DriveLetter):" }
        $evidence = [ordered]@{
            DriveLetter     = [string]$volume.DriveLetter
            FileSystemLabel = [string]$volume.FileSystemLabel
            FileSystem      = [string]$volume.FileSystem
            HealthStatus    = $healthStatus
        }
        $results += New-InfraPulseResult -Status $status -CheckName 'Storage' -Category 'Reliability' -ComputerName $Context.ComputerName -Target $volumeLabel -Message "Volume '$volumeLabel' reports health status '$healthStatus'." -ObservedValue $healthStatus -CriticalThreshold 'Health status must be Healthy' -Recommendation 'Run a file-system check during a maintenance window and validate the underlying disk health.' -Evidence $evidence -DurationMs ($stopwatch.Elapsed.TotalMilliseconds / [math]::Max($disks.Count + $volumes.Count, 1))
    }

    $summaryEvidence = [ordered]@{
        PhysicalDisks    = @($disks)
        FixedVolumes     = @($volumes)
        UnhealthyObjects = $unhealthyCount
    }
    $results += New-InfraPulseResult -Status 'Healthy' -CheckName 'Storage' -Category 'Reliability' -ComputerName $Context.ComputerName -Target 'Storage inventory' -Message "$($disks.Count - @($disks | Where-Object { [string]$_.HealthStatus -notin @('Healthy', '') }).Count) of $($disks.Count) physical disk(s) and $($volumes.Count - @($volumes | Where-Object { [string]$_.HealthStatus -notin @('Healthy', '') }).Count) of $($volumes.Count) fixed volume(s) report healthy status." -ObservedValue ($disks.Count + $volumes.Count - $unhealthyCount) -CriticalThreshold 'Health status must be Healthy' -Evidence $summaryEvidence -DurationMs $stopwatch.Elapsed.TotalMilliseconds

    return $results
}