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>.
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.
site1.erralert.com