Created
January 25, 2026 20:18
-
-
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.
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
| # ============================================================================== | |
| # 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