Private/Status.ps1

#Requires -Version 5.1

function Get-SMBeatHeartbeatObject {
    param(
        [Parameter(Mandatory = $true)]
        [string]$DataRoot
    )

    $json = Read-SMBeatTextFile -Path (Get-SMBeatHeartbeatPath -DataRoot $DataRoot)
    if ($null -eq $json) {
        return $null
    }

    ConvertFrom-SMBeatJson -Json $json
}

function Get-SMBeatScheduledTaskInfoSafe {
    param(
        [string]$TaskName = $script:SMBeatTaskName,
        $CimSession
    )

    $getParams = @{
        TaskName    = $TaskName
        TaskPath    = $script:SMBeatTaskPath
        ErrorAction = 'SilentlyContinue'
    }
    $infoParams = @{
        TaskName    = $TaskName
        TaskPath    = $script:SMBeatTaskPath
        ErrorAction = 'SilentlyContinue'
    }
    if ($CimSession) {
        $getParams['CimSession'] = $CimSession
        $infoParams['CimSession'] = $CimSession
    }

    $task = Get-ScheduledTask @getParams
    $info = $null
    if ($task) {
        $info = Get-ScheduledTaskInfo @infoParams
    }

    [PSCustomObject]@{
        Task = $task
        Info = $info
    }
}

function Get-SMBeatStatusInternal {
    param(
        [string]$Path,
        [string]$ComputerName,
        $CimSession
    )

    $dataRoot = Get-SMBeatDataRoot -Path $Path
    $config = Read-SMBeatConfig -DataRoot $dataRoot
    $interval = [int]$config.IntervalSec
    if ($interval -le 0) {
        $interval = $script:SMBeatDefaultIntervalSec
    }

    $label = $env:COMPUTERNAME
    if (-not [string]::IsNullOrWhiteSpace($ComputerName)) {
        $label = $ComputerName
    }
    elseif ($CimSession -and $CimSession.ComputerName) {
        $label = $CimSession.ComputerName
    }

    $taskPack = Get-SMBeatScheduledTaskInfoSafe -CimSession $CimSession
    $task = $taskPack.Task
    $info = $taskPack.Info

    $taskExists = $false
    $taskEnabled = $false
    $taskState = $null
    $lastRun = $null
    $nextRun = $null
    $lastResult = $null
    if ($task) {
        $taskExists = $true
        $taskState = [string]$task.State
        $taskEnabled = ($task.Settings.Enabled -eq $true)
    }
    if ($info) {
        $lastRun = $info.LastRunTime
        $nextRun = $info.NextRunTime
        $lastResult = $info.LastTaskResult
    }

    $hb = Get-SMBeatHeartbeatObject -DataRoot $dataRoot
    $lastSuccessUtc = $null
    $lastAttemptUtc = $null
    $lastError = ''
    $sampleAge = $null
    if ($hb) {
        if ($hb.LastSuccessUtc) {
            $lastSuccessUtc = ConvertFrom-SMBeatUtcString -Value ([string]$hb.LastSuccessUtc)
        }
        if ($hb.LastAttemptUtc) {
            $lastAttemptUtc = ConvertFrom-SMBeatUtcString -Value ([string]$hb.LastAttemptUtc)
        }
        $lastError = [string]$hb.LastError
        if ($hb.IntervalSec) {
            $interval = [int]$hb.IntervalSec
        }
    }

    $now = Get-SMBeatUtcNow
    if ($lastSuccessUtc) {
        $sampleAge = $now - $lastSuccessUtc
    }

    $fresh = $false
    if ($sampleAge) {
        $fresh = ($sampleAge.TotalSeconds -le (2 * $interval))
    }

    $taskRunning = $false
    if ($taskState -eq 'Running') {
        $taskRunning = $true
    }

    $isCollecting = ($taskEnabled -and $fresh -and $taskRunning)

    $samplesToday = 0
    $todayPath = Get-SMBeatSampleFilePath -DataRoot $dataRoot -Utc $now
    if (Test-Path -LiteralPath $todayPath) {
        $samplesToday = @(Get-Content -LiteralPath $todayPath | Where-Object { $_ }).Count
    }

    $mode = 'tcp445'
    if ($config -and $config.PSObject.Properties['Mode'] -and $config.Mode) {
        $mode = [string]$config.Mode
    }
    if ($hb -and $hb.PSObject.Properties['Mode'] -and $hb.Mode) {
        $mode = [string]$hb.Mode
    }

    [PSCustomObject]@{
        PSTypeName     = 'Merlin.SMBeat.Status'
        ComputerName   = $label
        Path           = $dataRoot
        TaskExists     = $taskExists
        TaskEnabled    = $taskEnabled
        TaskState      = $taskState
        LastRunTime    = $lastRun
        NextRunTime    = $nextRun
        LastTaskResult = $lastResult
        LastSuccessUtc = $lastSuccessUtc
        LastAttemptUtc = $lastAttemptUtc
        SampleAge      = $sampleAge
        IntervalSec    = $interval
        LastError      = $lastError
        IsCollecting   = $isCollecting
        HeartbeatFresh = $fresh
        SamplesToday   = $samplesToday
        SampleFile     = $todayPath
        TaskRunning    = $taskRunning
        Mode           = $mode
    }
}

function Wait-SMBeatHeartbeat {
    param(
        [string]$Path,
        [int]$TimeoutSec = 90,
        [int]$IntervalSec = 60
    )

    $deadline = (Get-SMBeatUtcNow).AddSeconds($TimeoutSec)
    do {
        $status = Get-SMBeatStatusInternal -Path $Path
        if ($status.HeartbeatFresh) {
            return $status
        }
        Start-Sleep -Seconds 2
    } while ((Get-SMBeatUtcNow) -lt $deadline)

    return (Get-SMBeatStatusInternal -Path $Path)
}