AutomateMyJob
Back to BlogPowerShell

Monitor Your System Health with a Custom PowerShell Dashboard

Chris Anderson11 min read

Monitor Your System Health with a Custom PowerShell Dashboard

Your computer has been acting slow lately. Is it the CPU? Memory? A runaway process? Low disk space? Instead of opening Task Manager, Resource Monitor, and Disk Management separately, what if you had one command that showed you everything?

Today we're building a PowerShell system health dashboard that gives you instant visibility into your computer's vital signs. One command, all the information you need.

What You'll Learn

  • How to query CPU, memory, and disk metrics in PowerShell
  • Building a formatted, color-coded health dashboard
  • Setting up alerts for critical thresholds
  • Monitoring Windows services and processes
  • Creating a continuous monitoring mode

Prerequisites

  • Windows 10/11 with PowerShell 5.1+
  • No additional modules required (uses built-in cmdlets)
  • Administrator rights for full service monitoring

The Manual Pain

When something feels wrong with your system, the investigation usually goes like this:

  1. Open Task Manager, stare at CPU graph
  2. Sort by memory usage, hunt for memory hogs
  3. Open This PC, check each drive's free space
  4. Open Services, scroll through hundreds of entries
  5. Check Event Viewer for errors
  6. Google the symptoms because none of that helped

What if instead you could type one command and get a clear picture of your system's health?

The Automated Solution

Our dashboard will show:

  1. System overview: Uptime, OS version, hostname
  2. CPU status: Current usage and top processes
  3. Memory status: Used/free RAM with percentage
  4. Disk status: Space on all drives with warnings
  5. Service status: Critical services health check
  6. Network status: Connection state and IP info

Step 1: Gathering System Information

Let's start by collecting basic system information:

powershell
1function Get-SystemOverview {
2    $os = Get-CimInstance Win32_OperatingSystem
3    $cs = Get-CimInstance Win32_ComputerSystem
4    
5    # Calculate uptime
6    $uptime = (Get-Date) - $os.LastBootUpTime
7    $uptimeString = "{0} days, {1} hours, {2} minutes" -f $uptime.Days, $uptime.Hours, $uptime.Minutes
8    
9    return [PSCustomObject]@{
10        ComputerName = $cs.Name
11        OS = $os.Caption
12        OSVersion = $os.Version
13        Architecture = $os.OSArchitecture
14        LastBoot = $os.LastBootUpTime
15        Uptime = $uptimeString
16        TotalRAM = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
17    }
18}

This gives us the foundation—knowing what system we're looking at and how long it's been running.

Step 2: Monitoring CPU Usage

CPU monitoring tells us if the processor is being overwhelmed:

powershell
1function Get-CPUStatus {
2    # Get overall CPU usage
3    $cpuUsage = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
4    
5    # Get top CPU-consuming processes
6    $topProcesses = Get-Process | 
7        Where-Object { $_.CPU -gt 0 } |
8        Sort-Object CPU -Descending | 
9        Select-Object -First 5 Name, 
10            @{N='CPU(s)';E={[math]::Round($_.CPU, 2)}},
11            @{N='Memory(MB)';E={[math]::Round($_.WorkingSet64 / 1MB, 2)}}
12    
13    # Determine status
14    $status = if ($cpuUsage -lt 50) { "Healthy" }
15              elseif ($cpuUsage -lt 80) { "Elevated" }
16              else { "Critical" }
17    
18    return [PSCustomObject]@{
19        UsagePercent = [math]::Round($cpuUsage, 1)
20        Status = $status
21        TopProcesses = $topProcesses
22    }
23}

The function not only reports CPU percentage but also identifies which processes are consuming the most resources.

Step 3: Monitoring Memory

Memory pressure is a common cause of system slowdowns:

powershell
1function Get-MemoryStatus {
2    $os = Get-CimInstance Win32_OperatingSystem
3    
4    $totalMemory = $os.TotalVisibleMemorySize / 1MB  # Convert KB to GB
5    $freeMemory = $os.FreePhysicalMemory / 1MB
6    $usedMemory = $totalMemory - $freeMemory
7    $usedPercent = [math]::Round(($usedMemory / $totalMemory) * 100, 1)
8    
9    # Get top memory consumers
10    $topMemory = Get-Process | 
11        Sort-Object WorkingSet64 -Descending | 
12        Select-Object -First 5 Name,
13            @{N='Memory(MB)';E={[math]::Round($_.WorkingSet64 / 1MB, 2)}},
14            @{N='Memory(GB)';E={[math]::Round($_.WorkingSet64 / 1GB, 2)}}
15    
16    $status = if ($usedPercent -lt 70) { "Healthy" }
17              elseif ($usedPercent -lt 90) { "Elevated" }
18              else { "Critical" }
19    
20    return [PSCustomObject]@{
21        TotalGB = [math]::Round($totalMemory, 2)
22        UsedGB = [math]::Round($usedMemory, 2)
23        FreeGB = [math]::Round($freeMemory, 2)
24        UsedPercent = $usedPercent
25        Status = $status
26        TopConsumers = $topMemory
27    }
28}

Step 4: Monitoring Disk Space

Low disk space causes all sorts of problems, from failed updates to application crashes:

powershell
1function Get-DiskStatus {
2    $disks = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
3        $totalGB = [math]::Round($_.Size / 1GB, 2)
4        $freeGB = [math]::Round($_.FreeSpace / 1GB, 2)
5        $usedGB = $totalGB - $freeGB
6        $freePercent = if ($totalGB -gt 0) { [math]::Round(($freeGB / $totalGB) * 100, 1) } else { 0 }
7        
8        $status = if ($freePercent -gt 20) { "Healthy" }
9                  elseif ($freePercent -gt 10) { "Warning" }
10                  else { "Critical" }
11        
12        [PSCustomObject]@{
13            Drive = $_.DeviceID
14            Label = $_.VolumeName
15            TotalGB = $totalGB
16            UsedGB = $usedGB
17            FreeGB = $freeGB
18            FreePercent = $freePercent
19            Status = $status
20        }
21    }
22    
23    return $disks
24}

Step 5: Monitoring Critical Services

Some Windows services are essential—if they stop, things break:

powershell
1function Get-ServiceStatus {
2    # Define critical services to monitor
3    $criticalServices = @(
4        @{Name = "wuauserv"; Display = "Windows Update"},
5        @{Name = "WinDefend"; Display = "Windows Defender"},
6        @{Name = "Spooler"; Display = "Print Spooler"},
7        @{Name = "BITS"; Display = "Background Intelligent Transfer"},
8        @{Name = "W32Time"; Display = "Windows Time"},
9        @{Name = "Dhcp"; Display = "DHCP Client"},
10        @{Name = "Dnscache"; Display = "DNS Client"},
11        @{Name = "EventLog"; Display = "Windows Event Log"}
12    )
13    
14    $serviceStatus = foreach ($svc in $criticalServices) {
15        $service = Get-Service -Name $svc.Name -ErrorAction SilentlyContinue
16        
17        if ($service) {
18            $status = if ($service.Status -eq "Running") { "Running" }
19                      elseif ($service.Status -eq "Stopped") { "Stopped" }
20                      else { $service.Status.ToString() }
21            
22            [PSCustomObject]@{
23                Name = $svc.Display
24                ServiceName = $svc.Name
25                Status = $status
26                StartType = $service.StartType.ToString()
27            }
28        }
29        else {
30            [PSCustomObject]@{
31                Name = $svc.Display
32                ServiceName = $svc.Name
33                Status = "Not Found"
34                StartType = "N/A"
35            }
36        }
37    }
38    
39    return $serviceStatus
40}

Step 6: Building the Dashboard Display

Now let's create a beautiful, color-coded dashboard output:

powershell
1function Show-Dashboard {
2    param (
3        [PSCustomObject]$System,
4        [PSCustomObject]$CPU,
5        [PSCustomObject]$Memory,
6        [array]$Disks,
7        [array]$Services
8    )
9    
10    Clear-Host
11    
12    # Helper function for colored status
13    function Write-Status {
14        param ([string]$Status)
15        switch ($Status) {
16            "Healthy" { Write-Host $Status -ForegroundColor Green -NoNewline }
17            "Running" { Write-Host $Status -ForegroundColor Green -NoNewline }
18            "Elevated" { Write-Host $Status -ForegroundColor Yellow -NoNewline }
19            "Warning" { Write-Host $Status -ForegroundColor Yellow -NoNewline }
20            "Critical" { Write-Host $Status -ForegroundColor Red -NoNewline }
21            "Stopped" { Write-Host $Status -ForegroundColor Red -NoNewline }
22            default { Write-Host $Status -ForegroundColor Gray -NoNewline }
23        }
24    }
25    
26    # Header
27    Write-Host "`n" 
28    Write-Host "╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
29    Write-Host "║              SYSTEM HEALTH DASHBOARD                            ║" -ForegroundColor Cyan
30    Write-Host "║              $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')                              ║" -ForegroundColor Cyan
31    Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
32    
33    # System Overview
34    Write-Host "`n┌─ SYSTEM OVERVIEW ────────────────────────────────────────────────┐" -ForegroundColor White
35    Write-Host "│ Computer: $($System.ComputerName)" -ForegroundColor White
36    Write-Host "│ OS: $($System.OS) ($($System.Architecture))" -ForegroundColor White
37    Write-Host "│ Uptime: $($System.Uptime)" -ForegroundColor White
38    Write-Host "└──────────────────────────────────────────────────────────────────┘" -ForegroundColor White
39    
40    # CPU Status
41    Write-Host "`n┌─ CPU STATUS ─────────────────────────────────────────────────────┐" -ForegroundColor White
42    Write-Host -NoNewline "│ Usage: $($CPU.UsagePercent)% - Status: "
43    Write-Status $CPU.Status
44    Write-Host ""
45    Write-Host "│" -ForegroundColor White
46    Write-Host "│ Top CPU Processes:" -ForegroundColor White
47    foreach ($proc in $CPU.TopProcesses) {
48        Write-Host "│   $($proc.Name): $($proc.'CPU(s)')s CPU, $($proc.'Memory(MB)')MB RAM" -ForegroundColor Gray
49    }
50    Write-Host "└──────────────────────────────────────────────────────────────────┘" -ForegroundColor White
51    
52    # Memory Status
53    Write-Host "`n┌─ MEMORY STATUS ──────────────────────────────────────────────────┐" -ForegroundColor White
54    Write-Host -NoNewline "│ Used: $($Memory.UsedGB)GB / $($Memory.TotalGB)GB ($($Memory.UsedPercent)%) - Status: "
55    Write-Status $Memory.Status
56    Write-Host ""
57    Write-Host "│ Free: $($Memory.FreeGB)GB available" -ForegroundColor White
58    Write-Host "│" -ForegroundColor White
59    Write-Host "│ Top Memory Consumers:" -ForegroundColor White
60    foreach ($proc in $Memory.TopConsumers) {
61        Write-Host "│   $($proc.Name): $($proc.'Memory(MB)')MB" -ForegroundColor Gray
62    }
63    Write-Host "└──────────────────────────────────────────────────────────────────┘" -ForegroundColor White
64    
65    # Disk Status
66    Write-Host "`n┌─ DISK STATUS ────────────────────────────────────────────────────┐" -ForegroundColor White
67    foreach ($disk in $Disks) {
68        Write-Host -NoNewline "│ $($disk.Drive) "
69        if ($disk.Label) { Write-Host -NoNewline "($($disk.Label)) " }
70        Write-Host -NoNewline "- $($disk.FreeGB)GB free of $($disk.TotalGB)GB ($($disk.FreePercent)% free) - "
71        Write-Status $disk.Status
72        Write-Host ""
73    }
74    Write-Host "└──────────────────────────────────────────────────────────────────┘" -ForegroundColor White
75    
76    # Service Status
77    Write-Host "`n┌─ CRITICAL SERVICES ──────────────────────────────────────────────┐" -ForegroundColor White
78    foreach ($svc in $Services) {
79        Write-Host -NoNewline "│ $($svc.Name): "
80        Write-Status $svc.Status
81        Write-Host ""
82    }
83    Write-Host "└──────────────────────────────────────────────────────────────────┘" -ForegroundColor White
84    
85    Write-Host ""
86}

The Complete Script

Here's the full, production-ready script:

powershell
1<#
2.SYNOPSIS
3    Displays a comprehensive system health dashboard in PowerShell.
4
5.DESCRIPTION
6    This script monitors and displays:
7    - System information and uptime
8    - CPU usage and top processes
9    - Memory usage and top consumers
10    - Disk space on all drives
11    - Critical Windows services status
12    
13    Supports continuous monitoring mode with configurable refresh.
14
15.PARAMETER Continuous
16    Run in continuous monitoring mode (refreshes automatically).
17
18.PARAMETER RefreshSeconds
19    Seconds between refreshes in continuous mode. Default: 5
20
21.PARAMETER ExportPath
22    Export results to a JSON file at this path.
23
24.EXAMPLE
25    .\SystemHealth.ps1
26    Display the dashboard once.
27
28.EXAMPLE
29    .\SystemHealth.ps1 -Continuous
30    Run continuous monitoring (Ctrl+C to stop).
31
32.EXAMPLE
33    .\SystemHealth.ps1 -Continuous -RefreshSeconds 10
34    Continuous monitoring with 10-second refresh.
35
36.NOTES
37    Author: Chris Anderson
38    Date: 2025-11-18
39    Version: 1.0
40    Requires: PowerShell 5.1 or higher
41#>
42
43[CmdletBinding()]
44param (
45    [Parameter(Mandatory = $false)]
46    [switch]$Continuous,
47    
48    [Parameter(Mandatory = $false)]
49    [ValidateRange(1, 300)]
50    [int]$RefreshSeconds = 5,
51    
52    [Parameter(Mandatory = $false)]
53    [string]$ExportPath
54)
55
56# ============================================================================
57# Functions
58# ============================================================================
59
60function Get-SystemOverview {
61    $os = Get-CimInstance Win32_OperatingSystem
62    $cs = Get-CimInstance Win32_ComputerSystem
63    
64    $uptime = (Get-Date) - $os.LastBootUpTime
65    $uptimeString = "{0}d {1}h {2}m" -f $uptime.Days, $uptime.Hours, $uptime.Minutes
66    
67    return [PSCustomObject]@{
68        ComputerName = $cs.Name
69        OS = $os.Caption
70        OSVersion = $os.Version
71        Architecture = $os.OSArchitecture
72        LastBoot = $os.LastBootUpTime
73        Uptime = $uptimeString
74        TotalRAM = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
75    }
76}
77
78function Get-CPUStatus {
79    $cpuUsage = (Get-CimInstance Win32_Processor | 
80        Measure-Object -Property LoadPercentage -Average).Average
81    
82    $topProcesses = Get-Process | 
83        Where-Object { $_.CPU -gt 0 } |
84        Sort-Object CPU -Descending | 
85        Select-Object -First 5 Name, 
86            @{N='CPU(s)';E={[math]::Round($_.CPU, 2)}},
87            @{N='Memory(MB)';E={[math]::Round($_.WorkingSet64 / 1MB, 2)}}
88    
89    $status = if ($cpuUsage -lt 50) { "Healthy" }
90              elseif ($cpuUsage -lt 80) { "Elevated" }
91              else { "Critical" }
92    
93    return [PSCustomObject]@{
94        UsagePercent = [math]::Round($cpuUsage, 1)
95        Status = $status
96        TopProcesses = $topProcesses
97    }
98}
99
100function Get-MemoryStatus {
101    $os = Get-CimInstance Win32_OperatingSystem
102    
103    $totalMemory = $os.TotalVisibleMemorySize / 1MB
104    $freeMemory = $os.FreePhysicalMemory / 1MB
105    $usedMemory = $totalMemory - $freeMemory
106    $usedPercent = [math]::Round(($usedMemory / $totalMemory) * 100, 1)
107    
108    $topMemory = Get-Process | 
109        Sort-Object WorkingSet64 -Descending | 
110        Select-Object -First 5 Name,
111            @{N='Memory(MB)';E={[math]::Round($_.WorkingSet64 / 1MB, 2)}}
112    
113    $status = if ($usedPercent -lt 70) { "Healthy" }
114              elseif ($usedPercent -lt 90) { "Elevated" }
115              else { "Critical" }
116    
117    return [PSCustomObject]@{
118        TotalGB = [math]::Round($totalMemory, 2)
119        UsedGB = [math]::Round($usedMemory, 2)
120        FreeGB = [math]::Round($freeMemory, 2)
121        UsedPercent = $usedPercent
122        Status = $status
123        TopConsumers = $topMemory
124    }
125}
126
127function Get-DiskStatus {
128    $disks = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
129        $totalGB = [math]::Round($_.Size / 1GB, 2)
130        $freeGB = [math]::Round($_.FreeSpace / 1GB, 2)
131        $usedGB = $totalGB - $freeGB
132        $freePercent = if ($totalGB -gt 0) { 
133            [math]::Round(($freeGB / $totalGB) * 100, 1) 
134        } else { 0 }
135        
136        $status = if ($freePercent -gt 20) { "Healthy" }
137                  elseif ($freePercent -gt 10) { "Warning" }
138                  else { "Critical" }
139        
140        [PSCustomObject]@{
141            Drive = $_.DeviceID
142            Label = $_.VolumeName
143            TotalGB = $totalGB
144            UsedGB = $usedGB
145            FreeGB = $freeGB
146            FreePercent = $freePercent
147            Status = $status
148        }
149    }
150    
151    return $disks
152}
153
154function Get-ServiceStatus {
155    $criticalServices = @(
156        @{Name = "wuauserv"; Display = "Windows Update"},
157        @{Name = "WinDefend"; Display = "Windows Defender"},
158        @{Name = "Spooler"; Display = "Print Spooler"},
159        @{Name = "BITS"; Display = "Background Transfer"},
160        @{Name = "Dhcp"; Display = "DHCP Client"},
161        @{Name = "Dnscache"; Display = "DNS Client"},
162        @{Name = "EventLog"; Display = "Event Log"}
163    )
164    
165    $serviceStatus = foreach ($svc in $criticalServices) {
166        $service = Get-Service -Name $svc.Name -ErrorAction SilentlyContinue
167        
168        if ($service) {
169            [PSCustomObject]@{
170                Name = $svc.Display
171                ServiceName = $svc.Name
172                Status = $service.Status.ToString()
173                StartType = $service.StartType.ToString()
174            }
175        }
176        else {
177            [PSCustomObject]@{
178                Name = $svc.Display
179                ServiceName = $svc.Name
180                Status = "Not Found"
181                StartType = "N/A"
182            }
183        }
184    }
185    
186    return $serviceStatus
187}
188
189function Show-Dashboard {
190    param (
191        [PSCustomObject]$System,
192        [PSCustomObject]$CPU,
193        [PSCustomObject]$Memory,
194        [array]$Disks,
195        [array]$Services
196    )
197    
198    Clear-Host
199    
200    function Write-Status {
201        param ([string]$Status)
202        switch ($Status) {
203            "Healthy" { Write-Host $Status -ForegroundColor Green -NoNewline }
204            "Running" { Write-Host $Status -ForegroundColor Green -NoNewline }
205            "Elevated" { Write-Host $Status -ForegroundColor Yellow -NoNewline }
206            "Warning" { Write-Host $Status -ForegroundColor Yellow -NoNewline }
207            "Critical" { Write-Host $Status -ForegroundColor Red -NoNewline }
208            "Stopped" { Write-Host $Status -ForegroundColor Red -NoNewline }
209            default { Write-Host $Status -ForegroundColor Gray -NoNewline }
210        }
211    }
212    
213    # Header
214    Write-Host ""
215    Write-Host "  ╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
216    Write-Host "  ║            SYSTEM HEALTH DASHBOARD                           ║" -ForegroundColor Cyan
217    Write-Host "  ║            $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')                            ║" -ForegroundColor Cyan
218    Write-Host "  ╚══════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
219    
220    # System Overview
221    Write-Host ""
222    Write-Host "  ┌─ SYSTEM ──────────────────────────────────────────────────────┐" -ForegroundColor White
223    Write-Host "  │ $($System.ComputerName) | $($System.OS)" -ForegroundColor White
224    Write-Host "  │ Uptime: $($System.Uptime) | RAM: $($System.TotalRAM)GB" -ForegroundColor Gray
225    Write-Host "  └───────────────────────────────────────────────────────────────┘" -ForegroundColor White
226    
227    # CPU Status
228    Write-Host ""
229    Write-Host "  ┌─ CPU ─────────────────────────────────────────────────────────┐" -ForegroundColor White
230    Write-Host -NoNewline "  │ Usage: $($CPU.UsagePercent)% ["
231    
232    # Progress bar
233    $barLength = 30
234    $filled = [math]::Round(($CPU.UsagePercent / 100) * $barLength)
235    $empty = $barLength - $filled
236    $barColor = if ($CPU.UsagePercent -lt 50) { "Green" } 
237                elseif ($CPU.UsagePercent -lt 80) { "Yellow" } 
238                else { "Red" }
239    Write-Host ("█" * $filled) -ForegroundColor $barColor -NoNewline
240    Write-Host ("░" * $empty) -ForegroundColor DarkGray -NoNewline
241    Write-Host "] "
242    
243    Write-Host "  │ Top: $($CPU.TopProcesses[0].Name) ($($CPU.TopProcesses[0].'CPU(s)')s)" -ForegroundColor Gray
244    Write-Host "  └───────────────────────────────────────────────────────────────┘" -ForegroundColor White
245    
246    # Memory Status
247    Write-Host ""
248    Write-Host "  ┌─ MEMORY ──────────────────────────────────────────────────────┐" -ForegroundColor White
249    Write-Host -NoNewline "  │ Used: $($Memory.UsedGB)GB / $($Memory.TotalGB)GB ["
250    
251    $filled = [math]::Round(($Memory.UsedPercent / 100) * $barLength)
252    $empty = $barLength - $filled
253    $barColor = if ($Memory.UsedPercent -lt 70) { "Green" } 
254                elseif ($Memory.UsedPercent -lt 90) { "Yellow" } 
255                else { "Red" }
256    Write-Host ("█" * $filled) -ForegroundColor $barColor -NoNewline
257    Write-Host ("░" * $empty) -ForegroundColor DarkGray -NoNewline
258    Write-Host "] $($Memory.UsedPercent)%"
259    
260    Write-Host "  │ Free: $($Memory.FreeGB)GB | Top: $($Memory.TopConsumers[0].Name)" -ForegroundColor Gray
261    Write-Host "  └───────────────────────────────────────────────────────────────┘" -ForegroundColor White
262    
263    # Disk Status
264    Write-Host ""
265    Write-Host "  ┌─ DISKS ───────────────────────────────────────────────────────┐" -ForegroundColor White
266    foreach ($disk in $Disks) {
267        $usedPercent = 100 - $disk.FreePercent
268        $filled = [math]::Round(($usedPercent / 100) * 20)
269        $empty = 20 - $filled
270        $barColor = if ($disk.FreePercent -gt 20) { "Green" } 
271                    elseif ($disk.FreePercent -gt 10) { "Yellow" } 
272                    else { "Red" }
273        
274        Write-Host -NoNewline "  │ $($disk.Drive) ["
275        Write-Host ("█" * $filled) -ForegroundColor $barColor -NoNewline
276        Write-Host ("░" * $empty) -ForegroundColor DarkGray -NoNewline
277        Write-Host "] $($disk.FreeGB)GB free ($($disk.FreePercent)%)"
278    }
279    Write-Host "  └───────────────────────────────────────────────────────────────┘" -ForegroundColor White
280    
281    # Services
282    Write-Host ""
283    Write-Host "  ┌─ SERVICES ────────────────────────────────────────────────────┐" -ForegroundColor White
284    $running = ($Services | Where-Object { $_.Status -eq "Running" }).Count
285    $total = $Services.Count
286    $stopped = ($Services | Where-Object { $_.Status -eq "Stopped" })
287    
288    Write-Host "  │ Running: $running/$total critical services" -ForegroundColor Green
289    
290    if ($stopped.Count -gt 0) {
291        Write-Host "  │ Stopped: $($stopped.Name -join ', ')" -ForegroundColor Red
292    }
293    Write-Host "  └───────────────────────────────────────────────────────────────┘" -ForegroundColor White
294    
295    Write-Host ""
296}
297
298function Export-HealthData {
299    param (
300        [string]$Path,
301        [PSCustomObject]$System,
302        [PSCustomObject]$CPU,
303        [PSCustomObject]$Memory,
304        [array]$Disks,
305        [array]$Services
306    )
307    
308    $data = @{
309        Timestamp = Get-Date -Format "o"
310        System = $System
311        CPU = @{
312            UsagePercent = $CPU.UsagePercent
313            Status = $CPU.Status
314        }
315        Memory = @{
316            TotalGB = $Memory.TotalGB
317            UsedGB = $Memory.UsedGB
318            FreeGB = $Memory.FreeGB
319            UsedPercent = $Memory.UsedPercent
320            Status = $Memory.Status
321        }
322        Disks = $Disks
323        Services = $Services
324    }
325    
326    $data | ConvertTo-Json -Depth 5 | Out-File -FilePath $Path -Encoding UTF8
327}
328
329# ============================================================================
330# Main Execution
331# ============================================================================
332
333do {
334    # Gather all metrics
335    $system = Get-SystemOverview
336    $cpu = Get-CPUStatus
337    $memory = Get-MemoryStatus
338    $disks = Get-DiskStatus
339    $services = Get-ServiceStatus
340    
341    # Display dashboard
342    Show-Dashboard -System $system -CPU $cpu -Memory $memory -Disks $disks -Services $services
343    
344    # Export if requested
345    if ($ExportPath) {
346        Export-HealthData -Path $ExportPath -System $system -CPU $cpu `
347            -Memory $memory -Disks $disks -Services $services
348        Write-Host "  Data exported to: $ExportPath" -ForegroundColor Gray
349    }
350    
351    if ($Continuous) {
352        Write-Host "  Press Ctrl+C to stop. Refreshing in $RefreshSeconds seconds..." -ForegroundColor DarkGray
353        Start-Sleep -Seconds $RefreshSeconds
354    }
355    
356} while ($Continuous)

How to Run This Script

Method 1: Single Check

powershell
1# Run once to see current status
2.\SystemHealth.ps1
3
4# Export results to JSON
5.\SystemHealth.ps1 -ExportPath "C:\Logs\health.json"

Method 2: Continuous Monitoring

powershell
1# Monitor with default 5-second refresh
2.\SystemHealth.ps1 -Continuous
3
4# Custom refresh rate
5.\SystemHealth.ps1 -Continuous -RefreshSeconds 10
6
7# Press Ctrl+C to stop

Method 3: Quick Function

Add this to your PowerShell profile for instant access:

powershell
1# Add to $PROFILE
2function health { & "C:\Scripts\SystemHealth.ps1" }
3function healthmon { & "C:\Scripts\SystemHealth.ps1" -Continuous }

Now just type health or healthmon anytime!

Customization Options

ParameterDefaultDescription
Continuous$falseEnable auto-refresh mode
RefreshSeconds5Seconds between refreshes
ExportPath(none)Save results to JSON file

Adding Custom Services

Edit the $criticalServices array to monitor services important to you:

powershell
1# Add SQL Server
2@{Name = "MSSQLSERVER"; Display = "SQL Server"},
3
4# Add IIS
5@{Name = "W3SVC"; Display = "IIS Web Server"},

Security Considerations

⚠️ Important notes:

  • This script only reads system information—it doesn't modify anything
  • No administrator rights needed for basic monitoring
  • Some service queries may require elevation for full details
  • Export files may contain system details—secure them appropriately
  • Safe to run on production systems

Common Issues & Solutions

IssueCauseSolution
CPU shows 0%WMI query timingRun again; first query can be stale
Services show "Not Found"Service not installedNormal—not all services exist on all systems
Memory numbers seem offCaching and buffersWindows uses available RAM for caching
Continuous mode flickersFast refreshIncrease RefreshSeconds

Taking It Further

Enhance the dashboard with these features:

  • Network monitoring: Add bandwidth usage and connection status
  • Event log alerts: Show recent errors from Windows logs
  • Temperature monitoring: Add CPU/GPU temps (requires additional tools)
  • Email alerts: Send notifications when thresholds are exceeded
  • Historical tracking: Store metrics over time for trend analysis
  • Remote monitoring: Check multiple computers from one console

Conclusion

You now have a powerful system health dashboard that gives you instant visibility into your computer's vital signs. No more clicking through multiple tools or wondering why things feel slow.

The beauty of this script is its simplicity—one command shows you everything. Run it when something feels off, or keep it running in continuous mode on a second monitor. Either way, you'll always know exactly what your system is doing.

This is the kind of tool that system administrators have been building for decades. Now you have one too, customized to your needs and ready to extend.

Your system has no more secrets. Happy monitoring!

Sponsored Content

Interested in advertising? Reach automation professionals through our platform.

Share this article