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:
- Open Task Manager, stare at CPU graph
- Sort by memory usage, hunt for memory hogs
- Open This PC, check each drive's free space
- Open Services, scroll through hundreds of entries
- Check Event Viewer for errors
- 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:
- System overview: Uptime, OS version, hostname
- CPU status: Current usage and top processes
- Memory status: Used/free RAM with percentage
- Disk status: Space on all drives with warnings
- Service status: Critical services health check
- Network status: Connection state and IP info
Step 1: Gathering System Information
Let's start by collecting basic system information:
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:
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:
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:
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:
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:
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:
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
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
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 stopMethod 3: Quick Function
Add this to your PowerShell profile for instant access:
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
| Parameter | Default | Description |
|---|---|---|
| Continuous | $false | Enable auto-refresh mode |
| RefreshSeconds | 5 | Seconds between refreshes |
| ExportPath | (none) | Save results to JSON file |
Adding Custom Services
Edit the $criticalServices array to monitor services important to you:
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
| Issue | Cause | Solution |
|---|---|---|
| CPU shows 0% | WMI query timing | Run again; first query can be stale |
| Services show "Not Found" | Service not installed | Normal—not all services exist on all systems |
| Memory numbers seem off | Caching and buffers | Windows uses available RAM for caching |
| Continuous mode flickers | Fast refresh | Increase 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.