A three-step runbook that produces one run history entry per server: full device information first — operating system, hardware, serial, disk, BIOS and network — then averaged CPU load, then averaged memory usage. Point it at a server group and it is a fleet inventory with the current load attached, which is a different thing from a monitoring dashboard and often the more useful one.
powershell
# ===== Step 1 of 3: 00-SE-GatherDeviceInformation.ps1 =====
# Gather Useful Computer Information with Reboot Check
#-----------------------------------------------------------
function Write-Log {
param($Message)
Write-Host "<WRITE-LOG = `"*$Message*`">"
}
Write-Log "Starting Computer Information Collection"
# OS Information
Write-Log "--- Operating System ---"
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
Write-Log "OS Name: $($osInfo.Caption)"
Write-Log "OS Version: $($osInfo.Version)"
Write-Log "OS Build: $($osInfo.BuildNumber)"
Write-Log "Architecture: $($osInfo.OSArchitecture)"
Write-Log "Install Date: $($osInfo.InstallDate)"
Write-Log "Last Boot Time: $($osInfo.LastBootUpTime)"
Write-Log "System Directory: $($osInfo.SystemDirectory)"
# System (Computer) Info
Write-Log "--- System ---"
$sysInfo = Get-CimInstance -ClassName Win32_ComputerSystem
Write-Log "Computer Name: $($sysInfo.Name)"
Write-Log "Domain: $($sysInfo.Domain)"
Write-Log "Role: $($sysInfo.Roles -join ', ')"
Write-Log "System Type: $($sysInfo.SystemType)"
Write-Log "Manufacturer: $($sysInfo.Manufacturer)"
Write-Log "Model: $($sysInfo.Model)"
# BIOS Serial Number
Write-Log "--- System Serial ---"
$serial = (Get-CimInstance -ClassName Win32_BIOS).SerialNumber
Write-Log "Serial Number: $serial"
# CPU
Write-Log "--- Processor ---"
$cpu = Get-CimInstance -ClassName Win32_Processor
Write-Log "Name: $($cpu.Name)"
Write-Log "Manufacturer: $($cpu.Manufacturer)"
Write-Log "Cores: $($cpu.NumberOfCores)"
Write-Log "Logical Processors: $($cpu.NumberOfLogicalProcessors)"
Write-Log "Max Clock Speed: $($cpu.MaxClockSpeed) MHz"
# Memory
Write-Log "--- Memory (RAM) ---"
$mem = Get-CimInstance -ClassName Win32_PhysicalMemory
$totalGB = ($mem | Measure-Object -Property Capacity -Sum).Sum / 1GB
Write-Log "Total RAM: $([math]::Round($totalGB, 1)) GB"
Write-Log "Modules Installed: $($mem.Count)"
# Disk (C:)
Write-Log "--- Disk (C:) ---"
$disk = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'"
Write-Log "Drive: C:\"
Write-Log "Size: $([math]::Round($disk.Size / 1GB, 1)) GB"
Write-Log "Free Space: $([math]::Round($disk.FreeSpace / 1GB, 1)) GB"
Write-Log "File System: $($disk.FileSystem)"
Write-Log "Volume Label: $($disk.VolumeName)"
# BIOS Details
Write-Log "--- BIOS ---"
$bios = Get-CimInstance -ClassName Win32_BIOS
Write-Log "Vendor: $($bios.SMBIOSBIOSVendor)"
Write-Log "Version: $($bios.SMBIOSBIOSVersion)"
Write-Log "Release Date: $($bios.ReleaseDate)"
# Network
Write-Log "--- Network (IPv4) ---"
$net = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled } | Select-Object -First 1
if ($net) {
Write-Log "MAC Address: $($net.MACAddress)"
Write-Log "IP Address: $(if ($net.IPAddress) { $net.IPAddress -join ', ' } else { 'None' })"
Write-Log "Default Gateway: $(if ($net.DefaultIPGateway) { $net.DefaultIPGateway -join ', ' } else { 'None' })"
} else {
Write-Log "No active IPv4 network adapters found"
}
# Reboot Check
Write-Log "--- Reboot Status ---"
$rebootRequired = $false
$registryPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending",
"HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttempts"
)
foreach ($path in $registryPaths) {
if (Test-Path $path) { $rebootRequired = $true }
}
# Check for Rename operations
if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name "PendingFileRenameOperations" -ErrorAction SilentlyContinue) {
$rebootRequired = $true
}
Write-Log "Reboot Required: $rebootRequired"
Write-Log "Computer Information Collection Complete"
# ===== Step 2 of 3: 01-CHECK-Usage-CPU.ps1 =====
function Write-Log {
param($Message)
Write-Host "<WRITE-LOG = `"*$Message*`">"
}
try {
$cpuValues = @()
# Collect CPU usage 5 times, 5 seconds apart
1..5 | ForEach-Object {
$cpuSample = Get-Counter '\Processor(_Total)\% Processor Time'
$cpuValue = $cpuSample.CounterSamples[0].CookedValue
$cpuValues += $cpuValue
Start-Sleep -Seconds 5
}
# Calculate and output the average
$avgCpu = [math]::Round(($cpuValues | Measure-Object -Average).Average, 2)
Write-Log "CPU Average Usage: $avgCpu %"
# Alert if average CPU exceeds 85%
if ($avgCpu -gt 85) {
Write-Error "CPU usage too high: $avgCpu %"
}
} catch {
Write-Log "Unable to gather CPU Information: Device not supported."
}
# ===== Step 3 of 3: 01-CHECK-Usage-RAM.ps1 =====
function Write-Log {
param($Message)
Write-Host "<WRITE-LOG = `"*$Message*`">"
}
try {
$ramValues = @()
# Collect RAM usage 5 times, 5 seconds apart
1..5 | ForEach-Object {
$ram = Get-WmiObject Win32_OperatingSystem
$totalRam = [math]::Round($ram.TotalVisibleMemorySize / 1MB, 2)
$freeRam = [math]::Round($ram.FreePhysicalMemory / 1MB, 2)
$usedRam = $totalRam - $freeRam
$ramUsagePercent = [math]::Round(($usedRam / $totalRam) * 100, 2)
$ramValues += $ramUsagePercent
Start-Sleep -Seconds 5
}
# Calculate and output the average
$avgRam = [math]::Round(($ramValues | Measure-Object -Average).Average, 2)
Write-Log "RAM Average Usage: $avgRam %"
# Alert if average RAM exceeds 85%
if ($avgRam -gt 85) {
Write-Error "RAM usage too high: $avgRam %"
}
}
catch {
Write-Log "Unable to gather RAM Information: Device not supported."
}Run it across your fleet
This script runs as-is on a single host. Paste it into ServerEngine to schedule it, run it on a whole server group in parallel, and keep the credentials out of the file — see the scripts documentation and the credential store.
More in Runbooks
Ready when you are.
Try ServerEngine free for 7 days.