Skip to content

Instantly share code, notes, and snippets.

@5j9
Created January 25, 2026 20:18
Show Gist options
  • Select an option

  • Save 5j9/d8bdb0e01534b1537328e0b4ae04d6f7 to your computer and use it in GitHub Desktop.

Select an option

Save 5j9/d8bdb0e01534b1537328e0b4ae04d6f7 to your computer and use it in GitHub Desktop.
PowerShell high-accuracy time synchronization script using HTTP headers (Google) to bypass restricted or blocked NTP/UDP 123 ports. Developed for system clock recovery during the Iran internet shutdowns of January 2026. Features dynamic outlier trimming and latency compensation.
# ==============================================================================
# SCRIPT NOTE:
# This script was developed to synchronize the system clock during the
# internet shutdowns in Iran in January 2026. During this period, NTP servers
# were restricted, and only a limited number of sites (like Google) were
# accessible. This script uses HTTP headers to bypass those restrictions.
#
# ACCURACY NOTE:
# Standard HTTP 'Date' headers only provide precision to the nearest second.
# While this script compensates for network latency (RTT/2), the base data
# has a built-in resolution of 1,000ms. Expect a final accuracy of ±500-800ms.
# This is ideal for general use but not for sub-millisecond precision.
# ==============================================================================
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Host "Please run this script as Administrator." -ForegroundColor Red
Start-Sleep -Seconds 3
exit
}
# --- CONFIGURATION ---
$iterations = 11
$offsets = @()
Write-Host "Starting adaptive time sync via Google HTTP ($iterations samples)..." -ForegroundColor Cyan
# --- DATA COLLECTION ---
for ($i = 1; $i -le $iterations; $i++) {
try {
$requestStart = Get-Date
$response = Invoke-WebRequest -Uri "https://www.google.com/" -Method Head -UseBasicParsing -TimeoutSec 10
$requestEnd = Get-Date
$webDateStr = $response.Headers['Date']
if ($webDateStr) {
$serverTimeUtc = [DateTime]::Parse($webDateStr, [System.Globalization.CultureInfo]::InvariantCulture)
$serverTimeLocal = $serverTimeUtc.ToLocalTime()
# Latency compensation (RTT / 2)
$rtt = ($requestEnd - $requestStart).TotalMilliseconds
$latency = $rtt / 2
$estimatedTrueTime = $serverTimeLocal.AddMilliseconds($latency)
# Offset = Truth - Local Clock
$sampleOffset = ($estimatedTrueTime - $requestEnd).TotalMilliseconds
$offsets += [PSCustomObject]@{
Offset = $sampleOffset
RTT = $rtt
}
Write-Host "Sample $i/$iterations : RTT = $($rtt.ToString('0.00')) ms | Offset = $($sampleOffset.ToString('0.00')) ms" -ForegroundColor DarkGray
}
} catch {
Write-Host "Sample $i failed: $($_.Exception.Message)" -ForegroundColor Red
}
if ($i -lt $iterations) { Start-Sleep -Seconds 1 }
}
# --- DYNAMIC TRIMMING & CALCULATION ---
if ($offsets.Count -ge 3) {
$sorted = $offsets | Sort-Object RTT
# Calculate trim amount (20% from each end)
$trimCount = [Math]::Max(1, [Math]::Floor($sorted.Count * 0.2))
$startIndex = $trimCount
$endIndex = $sorted.Count - 1 - $trimCount
$trimmed = $sorted[$startIndex..$endIndex]
$avgOffsetMs = ($trimmed | Measure-Object -Property Offset -Average).Average
Write-Host "------------------------------------------------"
Write-Host "Samples: Total=$($offsets.Count) | Trimmed=$($trimCount * 2) | Used=$($trimmed.Count)" -ForegroundColor Gray
Write-Host "Final Average Offset: $($avgOffsetMs.ToString('0.00')) ms" -ForegroundColor Cyan
# Apply the correction
$newTime = (Get-Date).AddMilliseconds($avgOffsetMs)
Set-Date -Date $newTime
Write-Host "System clock updated successfully." -ForegroundColor Green
Write-Host "Adjustment: $([Math]::Round($avgOffsetMs, 2)) ms" -ForegroundColor Yellow
} else {
Write-Host "Error: Not enough data points to calculate a reliable average." -ForegroundColor Red
}
Start-Sleep -Seconds 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment