Windows server health snapshot

A read-only Windows Server health snapshot that returns one compact row per host for uptime, disk pressure, memory headroom, stopped automatic services, and recent system errors.

Good For

  • server health checks
  • incident intake
  • patch window readiness
  • support handoff
  • baseline evidence

How to Use It

  1. Capture uptime first so recent reboots or long-running hosts are visible before deeper troubleshooting.
  2. Review disk free space by fixed drive and compare low-space drives with application, database, IIS, or log locations.
  3. If memory pressure is suspected, compare free memory with workload expectations and recent monitoring history.
  4. Review stopped automatic services, then confirm whether each service is intentionally disabled, delayed, or failing.
  5. Check recent system errors for disk, service-control, driver, update, or unexpected shutdown signals.
  6. Save the snapshot before making repair decisions so the ticket has a before-state for validation.

Execution Modes

  • local
  • remote-single-host
  • remote-host-list

Inputs and Outputs

Inputs

  • computer name
  • CSV or TXT server list
  • admin or delegated read access
  • expected service baseline
  • known disk thresholds

Outputs

  • verbose-console
  • csv

Command Starter

Safe to run: read-only

# ---------------------------------------------------------------------
# Operator inputs
# ---------------------------------------------------------------------
$ComputerNames = @('server01')
$OutputPath = '.\windows-server-health-snapshot.csv'

# ---------------------------------------------------------------------
# Collect a compact host-health row from each server
# ---------------------------------------------------------------------
$Results = foreach ($ComputerName in $ComputerNames) {
    try {
        Invoke-Command -ComputerName $ComputerName -ErrorAction Stop -ScriptBlock {
            # Uptime and memory context.
            $Os = Get-CimInstance -ClassName Win32_OperatingSystem
            $UptimeDays = [math]::Round(((Get-Date) - $Os.LastBootUpTime).TotalDays, 1)
            $FreeMemoryPercent = [math]::Round(($Os.FreePhysicalMemory / $Os.TotalVisibleMemorySize) * 100, 1)

            # Fixed-disk pressure. Track the lowest free-space percentage on the host.
            $Disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3'
            $LowestDiskFreePercent = ($Disks | ForEach-Object {
                if ($_.Size -gt 0) { [math]::Round(($_.FreeSpace / $_.Size) * 100, 1) }
            } | Measure-Object -Minimum).Minimum

            # Stopped automatic services are findings, not automatic proof of outage.
            $StoppedAutomaticServices = @(Get-Service |
                Where-Object { $_.StartType -eq 'Automatic' -and $_.Status -ne 'Running' })

            # Recent System log errors provide lightweight before-state evidence.
            $RecentSystemErrors = @(Get-WinEvent -FilterHashtable @{ LogName='System'; Level=2 } -MaxEvents 25 -ErrorAction SilentlyContinue)

            [pscustomobject]@{
                ComputerName                 = $env:COMPUTERNAME
                LastBootUpTime                = $Os.LastBootUpTime
                UptimeDays                    = $UptimeDays
                FreeMemoryPercent             = $FreeMemoryPercent
                LowestFixedDiskFreePercent    = $LowestDiskFreePercent
                StoppedAutomaticServiceCount  = $StoppedAutomaticServices.Count
                RecentSystemErrorCount        = $RecentSystemErrors.Count
            }
        }
    }
    catch {
        # Keep unreachable or access-denied systems visible instead of silently dropping them.
        [pscustomobject]@{
            ComputerName                 = $ComputerName
            LastBootUpTime                = $null
            UptimeDays                    = $null
            FreeMemoryPercent             = $null
            LowestFixedDiskFreePercent    = $null
            StoppedAutomaticServiceCount  = $null
            RecentSystemErrorCount        = $null
            Error                         = $_.Exception.Message
        }
    }
}

$Results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
$Results | Format-Table -AutoSize

Validation

  • The snapshot identifies whether disk, memory, service state, or recent system errors are likely contributing factors.
  • Any stopped automatic service is classified as expected, intentionally disabled, or needing service-specific triage.
  • Follow-up checks after repair show improved free space, resolved service state, or no repeat critical event.

Reporting

  • Copy the compact host-health summary into the incident record.
  • Attach the CSV when patch-window review or multi-server support triage needs a retained snapshot.
  • Use the shared reporting foundation when a future HTML/JSON/log package is needed across repeated runs.

Safety Notes

  • This snapshot is read-only and should not restart services or clear logs.
  • Do not treat every stopped automatic service as a failure; compare against the server role and change history.