Disk inventory + free space (Windows) powershell
Enumerates every physical disk (internal + external) and every volume. Reports capacity, free space, SMART health, drive type (SSD/HDD), bus type (USB / SATA / NVMe / SCSI), Windows disk number, drive letters, and per-partition details. Pair with capture.value and pick the path that matters — e.g. <code>volumes.C.free_gb</code>, <code>disks.disk_0.health</code>, or <code>any_unhealthy</code>.
YOUR_URL with your capture endpoint's POST URL
.
(Open this page from your capture object to have these auto-filled.)
# disk-inventory.ps1 — every physical disk + every volume.
# Sends: SMART health, bus/media type, drive letters, per-partition free space.
# Pair with capture.value to alert on any of these paths.
$Url = "YOUR_URL/disk"
$Disks = @{}
$Volumes = @{}
$AnyUnhealthy = $false
foreach ($d in (Get-Disk -ErrorAction SilentlyContinue)) {
$diskKey = "disk_$($d.Number)"
# Match the PhysicalDisk row for MediaType (SSD/HDD/Unspecified) and a
# second opinion on health. DeviceId on PhysicalDisk is a string version
# of the disk number.
$pd = Get-PhysicalDisk -ErrorAction SilentlyContinue |
Where-Object { "$($_.DeviceId)" -eq "$($d.Number)" } |
Select-Object -First 1
$partitions = @{}
$letters = @()
foreach ($p in (Get-Partition -DiskNumber $d.Number -ErrorAction SilentlyContinue)) {
$partKey = "p$($p.PartitionNumber)"
$partInfo = @{
number = [int]$p.PartitionNumber
size_gb = [math]::Round($p.Size / 1GB, 2)
type = "$($p.Type)"
letter = $null
label = $null
filesystem = $null
size_gb_fs = $null
free_gb = $null
used_gb = $null
free_pct = $null
}
if ($p.DriveLetter) {
$letter = "$($p.DriveLetter)"
$partInfo.letter = $letter
$letters += $letter
$vol = Get-Volume -DriveLetter $p.DriveLetter -ErrorAction SilentlyContinue
if ($vol -and $vol.Size -gt 0) {
$size = [double]$vol.Size
$rem = [double]$vol.SizeRemaining
$partInfo.label = "$($vol.FileSystemLabel)"
$partInfo.filesystem = "$($vol.FileSystem)"
$partInfo.size_gb_fs = [math]::Round($size / 1GB, 2)
$partInfo.free_gb = [math]::Round($rem / 1GB, 2)
$partInfo.used_gb = [math]::Round(($size - $rem) / 1GB, 2)
$partInfo.free_pct = [math]::Round(($rem / $size) * 100, 1)
# Also publish at top level under volumes.<letter> so capture.value
# paths can stay short: "volumes.C.free_gb" reads better than
# "disks.disk_0.partitions.p3.free_gb".
$Volumes[$letter] = @{
disk_number = [int]$d.Number
partition = [int]$p.PartitionNumber
label = "$($vol.FileSystemLabel)"
filesystem = "$($vol.FileSystem)"
size_gb = [math]::Round($size / 1GB, 2)
free_gb = [math]::Round($rem / 1GB, 2)
used_gb = [math]::Round(($size - $rem) / 1GB, 2)
free_pct = [math]::Round(($rem / $size) * 100, 1)
}
}
}
$partitions[$partKey] = $partInfo
}
$health = if ($pd) { "$($pd.HealthStatus)" } else { "$($d.HealthStatus)" }
$operational = if ($pd) { "$($pd.OperationalStatus)" } else { "$($d.OperationalStatus)" }
if ($health -and $health -ne 'Healthy') { $AnyUnhealthy = $true }
$Disks[$diskKey] = @{
number = [int]$d.Number
model = "$($d.FriendlyName)"
serial = "$($d.SerialNumber)"
bus_type = "$($d.BusType)" # USB, SATA, NVMe, SCSI, RAID, ...
media_type = if ($pd) { "$($pd.MediaType)" } else { 'Unknown' } # SSD, HDD, Unspecified
size_gb = [math]::Round($d.Size / 1GB, 2)
health = $health
operational = $operational
drive_letters = @($letters)
partition_count = $partitions.Count
partitions = $partitions
}
}
$Body = (@{
hostname = $env:COMPUTERNAME
disk_count = $Disks.Count
volume_count = $Volumes.Count
any_unhealthy = $AnyUnhealthy
disks = $Disks
volumes = $Volumes
}) | ConvertTo-Json -Compress -Depth 10
Invoke-RestMethod -Uri $Url -Method Post -Body $Body `
-ContentType "application/json" -TimeoutSec 30 | Out-Null
Recommended pairing
Add a capture.value check to this capture object.
Examples: json_path = volumes.C.free_gb, op = <, threshold = 10 (low free space on C:). json_path = any_unhealthy, op = ==, threshold = true (any failing drive, severity: crit). json_path = disks.disk_0.health, op = !=, threshold = Healthy (SMART status of physical disk 0).
What is the filename?
disk-inventory.ps1 — this is the suggested name for the downloaded file. Rename freely if you prefer.
site1.erralert.com