Created
September 2, 2025 15:20
-
-
Save abix-/9dc8c78e9556f63c1baa380e006165b7 to your computer and use it in GitHub Desktop.
uptime.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Start-InternetUptimeMonitor { | |
[CmdletBinding()] | |
param( | |
[string]$Target = '8.8.8.8', | |
[int]$SampleIntervalSeconds = 1, # how often to ping (default = 1s) | |
[int]$RefreshSeconds = 1, # how often to refresh the UI | |
[int]$TimeoutMilliseconds = 900, # ping timeout | |
[switch]$NoColor # disable colored output | |
) | |
# --- internal state --- | |
$samples = New-Object System.Collections.Generic.List[object] # each: @{ t = [DateTime]; ok = $true/$false; rtt = [int] } | |
$win1m = 60 | |
$win15m = 15 * 60 | |
$win1h = 60 * 60 | |
$windows = @(@{Name='1 min'; Sec=$win1m}, @{Name='15 min'; Sec=$win15m}, @{Name='1 hour'; Sec=$win1h}) | |
$ping = [System.Net.NetworkInformation.Ping]::new() | |
$sw = [System.Diagnostics.Stopwatch]::StartNew() | |
$lastSample = $sw.Elapsed | |
$lastRefresh = $sw.Elapsed | |
# Simple color helpers | |
function _w { param([string]$text,[string]$color='White') | |
if ($NoColor) { Write-Host $text; return } | |
Write-Host $text -ForegroundColor $color | |
} | |
function _bar { param([double]$pct,[int]$width=40) | |
$filled = [int][Math]::Round($pct / 100 * $width) | |
$empty = $width - $filled | |
'[' + ('#' * $filled) + ('-' * $empty) + ']' | |
} | |
function _prc { param([double]$p) '{0,6:N2} %' -f $p } | |
# Render the dashboard | |
function _render { | |
$now = [DateTime]::UtcNow | |
$cutMax = $now.AddSeconds(-$win1h) | |
# prune anything older than the largest window | |
while ($samples.Count -gt 0 -and $samples[0].t -lt $cutMax) { $samples.RemoveAt(0) } | |
# compute each window | |
$stats = foreach ($w in $windows) { | |
$cut = $now.AddSeconds(-$w.Sec) | |
$win = $samples.Where({ $_.t -ge $cut }) | |
$total = $win.Count | |
$ok = ($win | Where-Object { $_.ok }).Count | |
$pct = if ($total -gt 0) { 100.0 * $ok / $total } else { [double]::NaN } | |
[pscustomobject]@{ | |
Name = $w.Name | |
Total = $total | |
OK = $ok | |
Uptime = $pct | |
} | |
} | |
$last = if ($samples.Count) { $samples[-1] } else { $null } | |
$status = if ($last -and $last.ok) { 'ONLINE' } else { 'OFFLINE' } | |
$rttTxt = if ($last -and $last.rtt -ge 0) { "$($last.rtt) ms" } else { '—' } | |
Clear-Host | |
_w ('INTERNET UPTIME MONITOR'.PadRight(60,' ')) 'Cyan' | |
_w ("Target: $Target Last RTT: $rttTxt Samples kept: $($samples.Count)") 'DarkGray' | |
if ($NoColor) { | |
Write-Host ("Status: {0}" -f $status) | |
} else { | |
$c = if ($status -eq 'ONLINE') {'Green'} else {'Red'} | |
_w ("Status: {0}" -f $status) $c | |
} | |
Write-Host '' | |
foreach ($s in $stats) { | |
$p = $s.Uptime | |
$pct = if ([double]::IsNaN($p)) { 0 } else { $p } | |
$bar = _bar -pct $pct | |
$line = "{0,-7} {1} {2} (OK {3}/{4})" -f $s.Name, (_prc $pct), $bar, $s.OK, $s.Total | |
if ($NoColor) { Write-Host $line } | |
else { | |
$col = if ($pct -ge 99) {'Green'} elseif ($pct -ge 95) {'Yellow'} else {'Red'} | |
_w $line $col | |
} | |
} | |
Write-Host '' | |
_w ("Ping every {0}s • Refresh every {1}s • Timeout {2}ms • Quit: Ctrl+C" -f $SampleIntervalSeconds, $RefreshSeconds, $TimeoutMilliseconds) 'DarkGray' | |
} | |
# Main loop: decouple sampling from rendering | |
try { | |
while ($true) { | |
$now = $sw.Elapsed | |
# sample at fixed interval | |
if ( ($now - $lastSample).TotalSeconds -ge $SampleIntervalSeconds ) { | |
$lastSample = $now | |
$t = [DateTime]::UtcNow | |
try { | |
$reply = $ping.Send($Target, $TimeoutMilliseconds) | |
$ok = ($reply.Status -eq [System.Net.NetworkInformation.IPStatus]::Success) | |
$rtt = if ($ok) { [int]$reply.RoundtripTime } else { -1 } | |
} catch { | |
$ok = $false; $rtt = -1 | |
} | |
$samples.Add([pscustomobject]@{ t = $t; ok = $ok; rtt = $rtt }) | |
} | |
# refresh UI | |
if ( ($now - $lastRefresh).TotalSeconds -ge $RefreshSeconds ) { | |
$lastRefresh = $now | |
_render | |
} | |
Start-Sleep -Milliseconds 50 | |
} | |
} | |
finally { | |
$ping.Dispose() | |
} | |
} | |
Start-InternetUptimeMonitor |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment