site1.erralert.com

← System & uptime

Windows host agent — all metrics (one payload) powershell

The all-in-one agent: posts a single JSON blob with uptime, CPU, memory, every disk (size / free / SMART health / SSD-HDD-NVMe-USB type), selected services, pending-reboot state, pending Windows Updates, and 24h event-log error counts. Create ONE capture probe per host and point this at it — the probe page renders a full <strong>Host metrics</strong> dashboard automatically. Pair with <code>capture.freshness</code> (alert if the agent stops) plus <code>capture.value</code> checks on paths like <code>cpu.load_pct</code>, <code>memory.used_pct</code>, <code>min_disk_free_pct</code>, <code>updates.pending</code>, or <code>any_disk_unhealthy</code>.

Placeholders only. Before running, replace YOUR_URL with your capture endpoint's POST URL . (Open this page from your capture object to have these auto-filled.)
# host-agent.ps1 — Windows host metrics → one JSON payload per run.
#   Create one capture probe for this machine, paste its URL below, and
#   schedule this script (e.g. every 5 min). The probe page builds a
#   dashboard from the payload automatically.

$Url      = "YOUR_URL"                      # bare capture URL for THIS host
$Services = @("Spooler","MSSQLSERVER")      # services to report (edit me)

$ErrorActionPreference = "SilentlyContinue"
function Round2($n){ [math]::Round([double]$n, 2) }

# ---- host / uptime -------------------------------------------------------
$os   = Get-CimInstance Win32_OperatingSystem
$boot = $os.LastBootUpTime
$uptimeSec = [int]((Get-Date) - $boot).TotalSeconds

# ---- cpu / memory --------------------------------------------------------
$cpuLoad = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
$cores   = (Get-CimInstance Win32_Processor | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum
$memTotalGb = Round2 ($os.TotalVisibleMemorySize / 1MB)
$memFreeGb  = Round2 ($os.FreePhysicalMemory / 1MB)
$memUsedGb  = Round2 ($memTotalGb - $memFreeGb)
$memUsedPct = if ($memTotalGb -gt 0) { Round2 (100 * $memUsedGb / $memTotalGb) } else { 0 }

# ---- disks ---------------------------------------------------------------
$disks = @(); $volumes = @{}; $anyUnhealthy = $false; $minFreePct = 100
foreach ($v in (Get-Volume | Where-Object { $_.DriveLetter -and $_.Size -gt 0 })) {
  $sizeGb = Round2 ($v.Size / 1GB)
  $freeGb = Round2 ($v.SizeRemaining / 1GB)
  $freePct = if ($v.Size -gt 0) { Round2 (100 * $v.SizeRemaining / $v.Size) } else { 0 }
  $usedPct = Round2 (100 - $freePct)

  # Map the volume back to its physical disk for media/bus type + SMART health.
  $media = "Unknown"; $bus = $null; $health = $null
  $part = Get-Partition -DriveLetter $v.DriveLetter
  if ($part) {
    $d  = Get-Disk -Number $part.DiskNumber
    if ($d) { $bus = "$($d.BusType)"; $health = "$($d.HealthStatus)" }
    $pd = Get-PhysicalDisk | Where-Object { "$($_.DeviceId)" -eq "$($part.DiskNumber)" } | Select-Object -First 1
    if ($pd) { $media = "$($pd.MediaType)"; if ($pd.HealthStatus) { $health = "$($pd.HealthStatus)" } }
  }
  if ($health -and $health -ne "Healthy") { $anyUnhealthy = $true }
  if ($freePct -lt $minFreePct) { $minFreePct = $freePct }

  $disks += [ordered]@{
    letter = "$($v.DriveLetter)"; label = "$($v.FileSystemLabel)";
    size_gb = $sizeGb; free_gb = $freeGb; used_pct = $usedPct;
    media_type = $media; bus_type = $bus; health = $health
  }
  $volumes["$($v.DriveLetter)"] = [ordered]@{ free_gb = $freeGb; free_pct = $freePct; used_pct = $usedPct }
}

# ---- services ------------------------------------------------------------
$svc = @()
foreach ($name in $Services) {
  $s = Get-Service -Name $name
  if ($s) {
    $svc += [ordered]@{ name = "$($s.Name)"; display = "$($s.DisplayName)";
      status = "$($s.Status)"; start_type = "$($s.StartType)" }
  } else {
    $svc += [ordered]@{ name = $name; display = $name; status = "NotFound"; start_type = $null }
  }
}

# ---- pending reboot ------------------------------------------------------
$pendingReboot = $false
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") { $pendingReboot = $true }
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") { $pendingReboot = $true }
if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations) { $pendingReboot = $true }

# ---- pending Windows Updates --------------------------------------------
$updPending = $null; $updSecurity = $null
try {
  $session  = New-Object -ComObject Microsoft.Update.Session
  $searcher = $session.CreateUpdateSearcher()
  $result   = $searcher.Search("IsInstalled=0 and IsHidden=0")
  $updPending = $result.Updates.Count
  $updSecurity = (@($result.Updates | Where-Object { $_.Categories | Where-Object { $_.Name -eq "Security Updates" } })).Count
} catch { }

# ---- event-log errors (last 24h) ----------------------------------------
$since = (Get-Date).AddHours(-24)
$sysErr = @(Get-WinEvent -FilterHashtable @{ LogName="System"; Level=2; StartTime=$since }).Count
$appErr = @(Get-WinEvent -FilterHashtable @{ LogName="Application"; Level=2; StartTime=$since }).Count

# ---- assemble + post -----------------------------------------------------
$payload = [ordered]@{
  agent = "win-host"; v = 1; ts = (Get-Date).ToString("o")
  host = [ordered]@{ name = $env:COMPUTERNAME; os = "$($os.Caption)";
    uptime_sec = $uptimeSec; boot_time = $boot.ToString("o") }
  cpu = [ordered]@{ load_pct = [double]$cpuLoad; cores = [int]$cores }
  memory = [ordered]@{ total_gb = $memTotalGb; used_gb = $memUsedGb; used_pct = $memUsedPct }
  disks = $disks
  volumes = $volumes
  min_disk_free_pct = $minFreePct
  any_disk_unhealthy = $anyUnhealthy
  services = $svc
  pending_reboot = $pendingReboot
  updates = [ordered]@{ pending = $updPending; security_pending = $updSecurity }
  event_errors = [ordered]@{ system_24h = $sysErr; application_24h = $appErr }
}

$json = $payload | ConvertTo-Json -Depth 6 -Compress
Invoke-RestMethod -Uri $Url -Method Post -ContentType "application/json" -Body $json

Recommended pairing

Add a capture.value check to this capture object.
Good alerts: memory.used_pct > 90 (warn). min_disk_free_pct < 10 (crit). any_disk_unhealthy == true (crit). updates.security_pending > 0 (warn). pending_reboot == true (warn). Also add a capture.freshness check (e.g. 75 min) so you hear about it if the agent stops reporting.

What is the filename?

host-agent.ps1 — this is the suggested name for the downloaded file. Rename freely if you prefer.