You’re on your fourth coffee, your download speed feels like it’s coming through a dial-up modem, and your Zoom call looks like it’s been processed by Minecraft. You need to test your internet speed—but firing up a browser, dodging ads, and watching spinning gauges isn’t the vibe today.
Let’s do it like IT pros do—from the command line.
In this guide, you’ll learn how to use Speedtest CLI (the official command-line tool from Ookla) on Windows to test your internet connection like a tech-savvy ninja. We’ll start with simple usage, level up with automation in PowerShell, and hint at more powerful features hiding just beneath the surface.
Step 1: Download Speedtest CLI for Windows
Start by downloading the CLI tool from the official site:
👉 Download Speedtest CLI (Windows)
Unzip the contents, and inside you’ll find speedtest.exe. Put it somewhere practical like C:\Tools\Speedtest, or scatter it across your drive like digital confetti—your call.
(But seriously, add it to your system PATH for easier access from any directory.)
Step 2: Run Your First Speed Test
Open Command Prompt or PowerShell, and type:
C:\Tools\Speedtest\speedtest.exe

You’ll see:
- Your ISP
- Server location
- Ping (latency)
- Download speed
- Upload speed
- A shareable Result URL
It’s fast, clean, and totally browser-free. No ads, no popups, no mysterious “Install Our Extension!” buttons.
Want to Pick a Specific Server?
By default, Speedtest picks the nearest server automatically. But if you want to test a particular one (e.g., for consistency or curiosity), you can:
1. List Nearby Servers:
speedtest.exe --servers
2. Run the Test with a Specific Server ID:
speedtest.exe --server-id 12345
This is great when you’re trying to benchmark against a datacenter or a favorite ISP node.
Here’re the switches you can use with speedtest.exe
Switch | Description |
---|---|
-h , --help | Show help information |
-v | Increase verbosity (use multiple times like -vvv ) |
-V , --version | Print version number |
--accept-license | Accept the license agreement (needed for automation) |
--accept-gdpr | Accept GDPR agreement (required in the EU) |
--servers , -L | List nearby servers |
--server-id=<id> , -s | Use a specific server by ID |
--host=<hostname> , -o | Use server by hostname |
--selection-details | Show server selection information |
--format=json | Output in compact JSON |
--format=json-pretty | Output in pretty-printed JSON |
--format=csv , tsv , jsonl | Output in various machine-readable formats |
--output-header | Include header row for CSV/TSV |
--unit=MB/s , Mbps , MiB/s , etc. | Customize output unit (for human-readable only) |
--precision=<n> | Set decimal precision (default: 2) |
--interface=<name> , -I | Bind to a specific network interface |
--ip=<address> , -i | Bind to a specific local IP address |
--ca-certificate=<path> | Use custom CA certificate (advanced use case) |
--progress=yes|no , -p | Enable/disable the progress bar |
--progress-update-interval=<ms> | Set interval (100–1000 ms) for progress updates |
Basic PowerShell Automation
Let’s start automating with PowerShell, because typing the same command manually every hour is so last century.
Here’s a basic script to run a test and log it:
# Define full path to speedtest.exe (change this if needed)
$speedtestPath = "C:\Tools\Speedtest\speedtest.exe"
# Check if speedtest.exe exists
if (-Not (Test-Path $speedtestPath)) {
Write-Error "speedtest.exe not found at $speedtestPath. Please verify the path."
exit
}
# Run the speed test and parse JSON output
try {
$output = & $speedtestPath --accept-license --accept-gdpr --format json | ConvertFrom-Json
}
catch {
Write-Error "Failed to execute speedtest. Error: $_"
exit
}
# Create a structured log object
$log = [PSCustomObject]@{
Timestamp = Get-Date
Ping = $output.ping.latency
Download = [math]::Round($output.download.bandwidth / 125000, 2) # Mbps
Upload = [math]::Round($output.upload.bandwidth / 125000, 2) # Mbps
Server = $output.server.name
ISP = $output.isp
}
# Display results in console
Write-Host "`n=== Speedtest Results ===" -ForegroundColor Cyan
$log | Format-List
# OPTIONAL: Save results to CSV (uncomment the next line to enable logging)
# $log | Export-Csv -Path "C:\Tools\Speedtest\speedtest-log.csv" -Append -NoTypeInformation
💡 Pro Tip: The conversion bandwidth / 125000 gives you Mbps because 1 byte = 8 bits and 1 Mbps = 125,000 bytes per second.
Going Further: Extracting More Goodies
Let’s now use a slightly more advanced script based on one you may have seen online:
$speedtestcmd = & "C:\Tools\Speedtest\speedtest.exe" --accept-license -s 37149 -f json
$speedtestresult = $speedtestcmd | ConvertFrom-Json
$result = [PSCustomObject]@{
Timestamp = Get-Date
ISP = $speedtestresult.isp
Server = $speedtestresult.server.name
Location = "$($speedtestresult.server.location), $($speedtestresult.server.country)"
PingLatencyMs = $speedtestresult.ping.latency
JitterMs = $speedtestresult.ping.jitter
PacketLoss = if ($speedtestresult.packetLoss) { "$($speedtestresult.packetLoss * 100)%" } else { "N/A" }
DownloadMbps = [math]::Round($speedtestresult.download.bandwidth / 1MB * 8, 2)
UploadMbps = [math]::Round($speedtestresult.upload.bandwidth / 1MB * 8, 2)
ResultURL = $speedtestresult.result.url
}
$result

Bonus: Set Alerts and Toast Notifications
Why stop there? Let’s have PowerShell complain when your speeds drop below expectations:
if ($result.DownloadMbps -lt 100) {
Write-Warning "⚠️ Your download speed is under 100 Mbps!"
}
Or, if you’re feeling fancy, make Windows send you a toast notification:
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
$toastXml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
$toastXml.GetElementsByTagName("text")[0].AppendChild($toastXml.CreateTextNode("Speedtest Results"))
$toastXml.GetElementsByTagName("text")[1].AppendChild($toastXml.CreateTextNode("Download: $($result.DownloadMbps) Mbps, Upload: $($result.UploadMbps) Mbps"))
$toast = [Windows.UI.Notifications.ToastNotification]::new($toastXml)
$notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Speedtest CLI")
$notifier.Show($toast)
Boom. Speed alerts straight to your desktop like a proper sysadmin.
What Are Toast Notifications?
Toast notifications are the small pop-ups that appear in the bottom-right corner of your screen (like when Outlook says “You’ve got mail”). PowerShell can trigger these using Windows Runtime APIs — yes, you can be fancy now.
Full Script with Toast Notification & Comments
# ========================================
# Speedtest CLI with Toast Notification
# ========================================
# Path to speedtest.exe (adjust as needed)
$speedtestPath = "C:\Tools\Speedtest\speedtest.exe"
# Ensure speedtest.exe exists
if (-Not (Test-Path $speedtestPath)) {
Write-Error "speedtest.exe not found at: $speedtestPath"
exit
}
# Run speedtest with license/GDPR acceptance and JSON output
try {
$output = & $speedtestPath --accept-license --accept-gdpr --format json | ConvertFrom-Json
}
catch {
Write-Error "Error while running speedtest: $_"
exit
}
# Extract and convert results into a friendly object
$result = [PSCustomObject]@{
Timestamp = Get-Date
DownloadMbps = [math]::Round($output.download.bandwidth / 125000, 2)
UploadMbps = [math]::Round($output.upload.bandwidth / 125000, 2)
PingLatencyMs = $output.ping.latency
ISP = $output.isp
Server = $output.server.name
}
# Display results in console
Write-Host "`n=== Speedtest Results ===" -ForegroundColor Cyan
$result | Format-List
# ========================================
# Toast Notification Section
# ========================================
# Load Windows Runtime namespace for notifications
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
# Use a two-line text template
$toastTemplate = [Windows.UI.Notifications.ToastTemplateType]::ToastText02
$toastXml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($toastTemplate)
# Set the notification's text content safely
$textNodes = $toastXml.GetElementsByTagName("text")
if ($textNodes.Count -ge 2) {
$textNodes.Item(0).InnerText = "Speedtest Results"
$textNodes.Item(1).InnerText = "Download: $($result.DownloadMbps) Mbps, Upload: $($result.UploadMbps) Mbps"
}
else {
Write-Warning "Could not retrieve expected <text> elements from toast template."
exit
}
# Create the toast notification object
$toast = [Windows.UI.Notifications.ToastNotification]::new($toastXml)
# Show the notification using a named toast notifier
$notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Speedtest CLI")
$notifier.Show($toast)
What This Script Does:
- Runs Speedtest CLI
Executes a test and captures bandwidth, ping, ISP, etc. - Displays the results in PowerShell
Easy to check manually in the terminal - Sends a toast notification
With download & upload speed info, so you can see it even if the terminal is minimized

Optionally, you can schedule Regular Tests with Task Scheduler
- Open Task Scheduler
- Create a new task
- Set a trigger (e.g., every hour)
- Action: Start a program →
powershell.exe
- Add argument:
-ExecutionPolicy Bypass -File "C:\Scripts\SpeedTest.ps1"
Now your system checks itself before it wrecks itself—automatically.
Want to Go Even Deeper?
Inside the speedtest.zip package, there’s a lesser-known file: speedtest.md—a complete command-line reference that reveals even more options:
- Use custom units (MB/s, GiB/s, kibps, etc.)
- Output formats like csv, tsv, json-pretty, and jsonl
- Adjust decimal precision with –precision
- Bind tests to a specific network interface or IP
- Control progress display and verbosity
- Handle exit codes and errors with style
We’ll unpack that in Part 2: Speedtest CLI Deep Dive [I’m working on it now 🙂 ] —where things get really nerdy. You’ll learn how to integrate it with monitoring tools like Zabbix, parse CSVs, or even send results to a dashboard.
Summary
With speedtest.exe and a bit of PowerShell magic, you now have:
- A lightweight, fast, ad-free way to test internet speed
- Logging and historical monitoring
- Custom scripts with alerts, notifications, and flexible output
- A professional way to say, “It’s not me, it’s the ISP.”
And the best part? No browser tabs were harmed in the making of these tests.