Skip to content

Van PowerShell tot Smart Home

Van PowerShell tot Smart Home

Primary Menu
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
Light/Dark Button
  • Home
  • 🔧 Je netwerk echt meten met PowerShell
  • Powershell

🔧 Je netwerk echt meten met PowerShell

Vincent van Unen 2026-03-17 (Last updated: 2026-03-17) 9 minutes read
ChatGPT Image Mar 17, 2026, 01_17_55 PM

Iedereen kent het moment.

Teams call die hapert.
Download die blijft hangen op 2 MB/s.
Of die ene collega die zegt: “bij mij werkt het gewoon hoor…”

En dan begint het: speedtest.net openen, screenshot maken, weer vergeten.

Dus dacht ik: dit moet slimmer kunnen.

🚀 Waarom ik dit script heb gemaakt

In mijn HomeLab én bij klanten wilde ik niet alleen weten hoe snel de verbinding is, maar vooral:

  • Welke adapter wordt gebruikt?
  • Zit je op WiFi of bekabeld?
  • Wat is je publieke IP?
  • Welke DNS gebruik je?
  • Waar staat die testserver eigenlijk?

En vooral: ik wil logging. Altijd.

Niet gokken, maar data.

Daarom heb ik een PowerShell script gebouwd dat:

✔ Speedtest draait via de officiële Ookla CLI
✔ Netwerkdata verzamelt
✔ Alles netjes wegschrijft naar JSON én CSV
✔ Logs bijhoudt (ook handig voor Intune / troubleshooting)

🧠 Wat maakt dit script anders?

Dit is geen simpele “run speedtest en klaar”.

Het script:

  • Detecteert je actieve netwerkadapter
  • Haalt publieke IP op via meerdere bronnen (fallback logic 💪)
  • Probeert je SSID te achterhalen (best effort, want Windows…)
  • Verrijkt data met geolocation
  • Logt alles gestructureerd
  • Draait ook volledig silent (handig voor automation / Intune)

Oftewel: dit is production-ready spul

📦 Het script

Hieronder de volledige versie:

[CmdletBinding(SupportsShouldProcess=$true)]
param(
[switch]$Silent,
[string]$LogName = "NetworkSpeedTest",
[string]$OutputFolder = "C:\log"
)

<#
.NOTES
===========================================================================
Created on: 2026-03-15
Created by: Vincent van Unen
Filename: sca-commandlinespeedtest.ps1
===========================================================================
.DESCRIPTION
PowerShell script to perform a network speed test using Ookla's Speedtest CLI, gather network information, and log results in structured JSON and CSV formats. The script includes robust error handling, logging, and is designed to run in both interactive and silent modes.
.SYNOPSIS
This script performs a network speed test using Ookla's Speedtest CLI, gathers detailed network information, and logs results in structured JSON and CSV formats. It includes robust error handling and can run in both interactive and silent modes.
.PARAMETER Silent
Run the script in silent mode (no console output, only logs).
#>


# ==============================
# Helper: Console + Log Writers
# ==============================
function Write-Console {
param(
[Parameter(Mandatory=$true)][string]$Message,
[ValidateSet("White","Yellow","Green","Cyan","Red","Gray")][string]$Color = "White"
)
if (-not $Silent) {
Write-Host $Message -ForegroundColor $Color
}
}

# ===================================
# Function: Get SSID (best effort)
# ===================================
function Get-CurrentSSID {
try {
# Gebruik netsh, match alleen "SSID" (niet "BSSID")
$w = netsh wlan show interfaces 2>$null | Select-String -Pattern "^\s*SSID\s*:"
if ($w) {
$raw = ($w -split ":",2)[1].Trim()
if ($raw -and $raw -ne "SSID") { return $raw }
}
} catch { }

try {
# Fallback via net connection profile
$cp = Get-NetConnectionProfile | Where-Object { $_.InterfaceAlias -like "*Wi-Fi*" -or $_.InterfaceAlias -like "*Wireless*" } | Select-Object -First 1
if ($cp) { return $cp.Name }
} catch { }

try {
# Legacy WMI fallback
$wifiAdapter = Get-WmiObject -Class Win32_NetworkAdapter | Where-Object { $_.Name -like "*Wi-Fi*" -or $_.Name -like "*Wireless*" } | Select-Object -First 1
if ($wifiAdapter) {
$wifiConfig = Get-WmiObject -Class Win32_NetworkAdapterConfiguration | Where-Object { $_.Index -eq $wifiAdapter.Index -and $_.IPEnabled -eq $true }
if ($wifiConfig) { return $wifiConfig.Description }
}
} catch { }

return $null
}

# ==============================
# Administrator Check
# ==============================
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Console "This script requires administrator privileges." "Yellow"
if (-not $Silent) { Read-Host "Press Enter to exit" }
exit 1
}

# ==============================
# Global/Script Configuration
# ==============================
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine -Force -WarningAction Ignore -ErrorAction Ignore
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Force -WarningAction Ignore -ErrorAction Ignore
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser -Force -WarningAction Ignore -ErrorAction Ignore
$MaximumFunctionCount = 16384
$MaximumVariableCount = 16384

# Dirs
$XIPMyModuleDir1 = "C:\temp"
$XIPMyModuleDir2 = "C:\tmp"
$XIPMyModuleDir3 = "C:\log"

foreach ($dir in @($XIPMyModuleDir1,$XIPMyModuleDir2,$XIPMyModuleDir3,$OutputFolder)) {
if (!(Test-Path -Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
}

# Script meta
$ScriptAuthor = "Vincent van Unen"
$ScripVersion = "1.0.1"
$ScriptChangeDate = (Get-Date -Format 'yyyy-MM-dd')
$ScriptChangeLog = "Fixed Get-CurrentSSID scope + math rounders"
$ScriptCurrentUser = $env:UserName
$ScriptRunningDevice = $env:COMPUTERNAME
$Getcurrentdate = Get-Date -Format 'yyyy-MM-dd'
$NowStamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'

# Speedtest config
$speedtestVersion = "1.2.0"
$speedtestUrl = "https://install.speedtest.net/app/cli/ookla-speedtest-$speedtestVersion-win64.zip"
$tempPath = Join-Path $env:TEMP "speedtest_cli_$NowStamp"
$zipFile = Join-Path $env:TEMP "speedtest_$NowStamp.zip"

# Logging file
$LogFile = Join-Path $XIPMyModuleDir3 ("{0} {1}.log" -f $LogName, $Getcurrentdate)

# ==============================
# Logger
# ==============================
function WriteToLogFile {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False)]
[ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")]
[String] $Level = "INFO",

[Parameter(Mandatory=$True)]
[string] $Message,

[Parameter(Mandatory=$False)]
[string] $logfile = $LogFile
)
if ($Message -eq " ") {
Add-Content $logfile -Value " " -ErrorAction SilentlyContinue
} else {
$Date = (Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss.fff')
Add-Content $logfile -Value "[$Date] [$Level] $Message" -ErrorAction SilentlyContinue
}
}

# ==============================
# Transcript
# ==============================
$TranscriptFile = Join-Path $XIPMyModuleDir3 ("{0}_{1}_Transcript.log" -f $Getcurrentdate, $LogName)
try { Start-Transcript -Path $TranscriptFile -ErrorAction SilentlyContinue | Out-Null } catch {}

# ==============================
# Initial Log Lines
# ==============================
WriteToLogFile -Message "Current Date = $Getcurrentdate"
WriteToLogFile -Message "Script Author = $ScriptAuthor"
WriteToLogFile -Message "Script Version = $ScripVersion"
WriteToLogFile -Message "Script ChangeDate = $ScriptChangeDate"
WriteToLogFile -Message "Current User = $ScriptCurrentUser"
WriteToLogFile -Message "Current Device = $ScriptRunningDevice"

# ===================================
# Function: Get Network Information
# ===================================
function Get-NetworkInfo {
Write-Console "`nGathering network information..." "Cyan"
WriteToLogFile -Level "INFO" -Message "Gathering network information"

# Active adapter (exclude loopback)
$activeAdapter = Get-NetAdapter | Where-Object { $_.Status -eq "Up" -and $_.InterfaceType -ne "Software Loopback" } | Select-Object -First 1

if (-not $activeAdapter) {
WriteToLogFile -Level "ERROR" -Message "No active network adapter found."
throw "No active network adapter found."
}

# IP config for active adapter
$ipConfig = Get-NetIPConfiguration | Where-Object { $_.NetAdapter -and $_.NetAdapter.Name -eq $activeAdapter.Name }

# DNS (IPv4)
$dnsServersObj = Get-DnsClientServerAddress | Where-Object { $_.InterfaceAlias -eq $activeAdapter.Name -and $_.AddressFamily -eq 2 }
$dnsList = @()
if ($dnsServersObj) {
foreach ($o in $dnsServersObj) {
if ($o.ServerAddresses) { $dnsList += $o.ServerAddresses }
}
}

# Public IP (try multiple sources)
$publicIp = $null
$publicIpSources = @(
"https://api.ipify.org",
"https://icanhazip.com",
"https://ipinfo.io/ip"
)
foreach ($source in $publicIpSources) {
try {
$r = Invoke-RestMethod -Uri $source -TimeoutSec 5
if ($r) {
$publicIp = $r.ToString().Trim()
break
}
} catch { continue }
}

# Compute local fields safely
$localIPv4 = $ipConfig.IPv4Address.IPAddress
$prefixLen = $ipConfig.IPv4Address.PrefixLength
$gw = $ipConfig.IPv4DefaultGateway.NextHop

return @{
ActiveAdapter = $activeAdapter
IPConfig = $ipConfig
DNSServers = $dnsList
PublicIP = $publicIp
DefaultGateway = $gw
LocalIP = $localIPv4
SubnetMask = $prefixLen
}
}

# ===================================
# Main
# ===================================
$ResultsObject = $null
$JsonOut = Join-Path $OutputFolder ("SpeedTest_{0}_{1}.json" -f $env:COMPUTERNAME,$NowStamp)
$CsvOut = Join-Path $OutputFolder ("SpeedTest_{0}_{1}.csv" -f $env:COMPUTERNAME,$NowStamp)

try {
# 1) Netwerk info
$networkInfo = Get-NetworkInfo

# Log public/private quick
try {
$GetpublicIP = $networkInfo.PublicIP
} catch { $GetpublicIP = $null }
try {
$GetprivateIP = (Get-NetIPAddress | Where-Object { $_.AddressState -eq "Preferred" -and $_.ValidLifetime -lt "24:00:00" -and $_.AddressFamily -eq 'IPv4' } | Select-Object -First 1).IPAddress
} catch { $GetprivateIP = $null }

WriteToLogFile -Message "Current Public IP = $GetpublicIP"
WriteToLogFile -Message "Current Private IP = $GetprivateIP"
WriteToLogFile -Message "Active Adapter = $($networkInfo.ActiveAdapter.Name) / $($networkInfo.ActiveAdapter.InterfaceDescription)"

# 2) Download Speedtest CLI
Write-Console "Downloading Speedtest CLI..." "Green"
WriteToLogFile -Message "Downloading Speedtest from $speedtestUrl"
Invoke-WebRequest -Uri $speedtestUrl -OutFile $zipFile -UseBasicParsing -ErrorAction Stop

# 3) Extract
Write-Console "Extracting files..." "Green"
WriteToLogFile -Message "Extracting to $tempPath"
Expand-Archive -Path $zipFile -DestinationPath $tempPath -Force -ErrorAction Stop

# Locate speedtest.exe (support nested folder structure)
$speedtestExe = Get-ChildItem -Path $tempPath -Filter "speedtest.exe" -Recurse | Select-Object -First 1
if (-not $speedtestExe) {
throw "speedtest.exe not found after extraction."
}

# 4) Run speed test
Write-Console "Running speed test..." "Green"
WriteToLogFile -Message "Starting speed test"
Push-Location $speedtestExe.Directory.FullName
$ResultsJson = & .\speedtest.exe --accept-license --accept-gdpr --format=json
Pop-Location

Write-Console "Speed test completed!" "Green"
WriteToLogFile -Message "Speed test completed"

if (-not $Silent) { Clear-Host }

# 5) Parse + compute metrics (FIXED rounding)
$results = $ResultsJson | ConvertFrom-Json
$downloadMbps = [math]::Round($results.download.bandwidth * 8 / 1MB, 2)
$uploadMbps = [math]::Round($results.upload.bandwidth * 8 / 1MB, 2)
$pingLatency = [math]::Round($results.ping.latency, 2)
$jitter = [math]::Round($results.ping.jitter, 2)
$packetLoss = $results.packetLoss

# 6) Geo info (best effort)
$geoInfo = $null
try {
if ($networkInfo.PublicIP) {
$geoInfo = Invoke-RestMethod -Uri ("http://ip-api.com/json/{0}" -f $networkInfo.PublicIP) -TimeoutSec 10
}
} catch {
WriteToLogFile -Level "WARN" -Message "Could not retrieve geolocation information: $($_.Exception.Message)"
}

# 7) SSID (function now defined!)
$SSID = Get-CurrentSSID

# 8) Compose single PSCustomObject
$ResultsObject = [PSCustomObject]@{
# Speed Test Results
SpeedTestDateTime = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
SSID = $SSID
DownloadSpeed_Mbps = $downloadMbps
UploadSpeed_Mbps = $uploadMbps
PingLatency_ms = $pingLatency
Jitter_ms = $jitter
PacketLoss_Percent = $packetLoss
ISP = $results.isp
TestServer = "$($results.server.name) - $($results.server.location), $($results.server.country)"
TestURL = $results.result.url

# Network Information
ActiveAdapter = $networkInfo.ActiveAdapter.Name
AdapterType = $networkInfo.ActiveAdapter.InterfaceDescription
LinkSpeed = $networkInfo.ActiveAdapter.LinkSpeed
MACAddress = $networkInfo.ActiveAdapter.MacAddress
LocalIP = ("{0}/{1}" -f $networkInfo.LocalIP, $networkInfo.SubnetMask)
DefaultGateway = $networkInfo.DefaultGateway
PublicIP = $networkInfo.PublicIP
DNSServers = ($networkInfo.DNSServers -join ", ")
ConnectionState = $networkInfo.ActiveAdapter.Status

# Geolocation Information
Country = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.country } else { "N/A" }
Region = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.regionName } else { "N/A" }
City = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.city } else { "N/A" }
ZipCode = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.zip } else { "N/A" }
Latitude = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.lat } else { "N/A" }
Longitude = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.lon } else { "N/A" }
Timezone = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.timezone } else { "N/A" }
GeoISP = if ($geoInfo -and $geoInfo.status -eq "success") { $geoInfo.isp } else { "N/A" }

# Script/Host context
ScriptAuthor = $ScriptAuthor
ScriptVersion = $ScripVersion
ScriptChangeDate = $ScriptChangeDate
RunUser = $ScriptCurrentUser
RunDevice = $ScriptRunningDevice
}

# 9) Log key metrics
WriteToLogFile -Message "Download: $downloadMbps Mbps | Upload: $uploadMbps Mbps | Ping: $pingLatency ms | Jitter: $jitter ms | Loss: $packetLoss"
WriteToLogFile -Message "Server: $($ResultsObject.TestServer) | ISP: $($ResultsObject.ISP)"
WriteToLogFile -Message "PublicIP: $($ResultsObject.PublicIP) | LocalIP: $($ResultsObject.LocalIP)"

# 10) Persist JSON + CSV
$ResultsObject | ConvertTo-Json -Depth 6 | Out-File -FilePath $JsonOut -Encoding utf8
$ResultsObject | Export-Csv -NoTypeInformation -Delimiter ';' -Encoding UTF8 -Path $CsvOut
WriteToLogFile -Message "Saved JSON to $JsonOut"
WriteToLogFile -Message "Saved CSV to $CsvOut"

} catch {
WriteToLogFile -Level "ERROR" -Message $_.Exception.Message
Write-Console "Error: $($_.Exception.Message)" "Red"
} finally {
# Cleanup
try { Set-Location $env:TEMP } catch {}
foreach ($p in @($zipFile,$tempPath)) {
try {
if (Test-Path $p) {
if ((Get-Item $p) -is [System.IO.DirectoryInfo]) {
Remove-Item $p -Recurse -Force -ErrorAction SilentlyContinue
} else {
Remove-Item $p -Force -ErrorAction SilentlyContinue
}
WriteToLogFile -Level "DEBUG" -Message "Cleaned up $p"
}
} catch {}
}

# Transcript stop & copy to IME logs
try { Stop-Transcript | Out-Null } catch {}
try {
$imeLogs = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs"
if (!(Test-Path $imeLogs)) { New-Item -ItemType Directory -Path $imeLogs | Out-Null }
Copy-Item -Path $TranscriptFile -Destination $imeLogs -Force -ErrorAction SilentlyContinue
WriteToLogFile -Message "Transcript copied to $imeLogs"
} catch {}
}

# Final output to pipeline for programmatic use
if ($ResultsObject) {
$ResultsObject
}

if (-not $Silent) {
Read-Host "Press Enter to exit"
}

👉 Tip: op je website kun je hier een “copy” knop bij zetten — werkt altijd lekker.

📊 Wat krijg je eruit?

Na het draaien van het script krijg je:

JSON output (perfect voor automation)

  • Ideaal voor API’s, dashboards of logging pipelines

CSV output (lekker voor Excel)

  • Snel analyseren
  • Trends bekijken

Log file

  • Volledige run geschiedenis
  • Errors + debug info

🔍 Voorbeeld van data die je krijgt

  • Download / upload snelheid (Mbps)
  • Ping + jitter + packet loss
  • ISP + testserver
  • Adapter + MAC address
  • DNS servers
  • Public & private IP
  • Locatie (land, stad, timezone)

Kort gezegd: alles wat je nodig hebt om een netwerkprobleem écht te begrijpen

🧰 Waar gebruik ik dit voor?

Een paar real-life use cases:

💼 Intune monitoring

Silent draaien op endpoints → resultaten verzamelen

🏠 HomeLab insights

WiFi vs bekabeld vergelijken (spoiler: WiFi verliest altijd 😄)

🧑‍💻 Troubleshooting bij klanten

Niet meer discussiëren — gewoon data laten zien

📈 Performance logging

Periodiek draaien → trends ontdekken


⚠️ Kleine kanttekeningen

  • Admin rechten zijn verplicht
  • Speedtest CLI wordt gedownload (internet nodig)
  • Geolocation is “best effort” (API afhankelijk)

💡 Bonus tip

Wil je dit naar een hoger niveau tillen?

Combineer dit met:

  • Task Scheduler (periodiek meten)
  • Azure Log Analytics
  • Power BI dashboard

En ineens heb je enterprise-level netwerk monitoring… met PowerShell.

🎯 Conclusie

Dit script is ontstaan uit frustratie, maar geëindigd als iets wat ik nu standaard gebruik.

Geen nattevingerwerk meer.
Geen “het zal wel aan WiFi liggen”.

Gewoon:

👉 meten
👉 loggen
👉 weten

About the Author

Vincent van Unen

Administrator

Visit Website View All Posts

Post navigation

Previous: Slimme ESPHome multisensor: UN-SENSOR-12

Related Stories

ChatGPT Image Mar 13, 2026, 05_39_33 AM
  • Azure
  • Powershell

🔎 Even snel de Tenant ID van een domein ophalen met PowerShell

Vincent van Unen 2026-03-13
ChatGPT Image Mar 13, 2026, 10_06_00 AM
  • Azure
  • Powershell

Powershell : Tijdelijke toegang zonder gedoe: Temporary Access Pass automatiseren

Vincent van Unen 2026-03-13
ChatGPT Image Mar 11, 2026, 02_16_25 PM
  • Intune
  • Powershell

Powershell – 🔥 Windows Firewall automatisch herstellen met Intune Proactive Remediation

Vincent van Unen 2026-03-11

Recent Posts

  • 🔧 Je netwerk echt meten met PowerShell
  • Slimme ESPHome multisensor: UN-SENSOR-12
  • 🔎 Even snel de Tenant ID van een domein ophalen met PowerShell
  • Powershell : Tijdelijke toegang zonder gedoe: Temporary Access Pass automatiseren
  • Home Assistant – Automation: als infra-bewaker: van “alles draait” naar “hé, wat ligt eruit?”

Recent Comments

No comments to show.

You May Have Missed

ChatGPT Image Mar 17, 2026, 01_17_55 PM
  • Powershell

🔧 Je netwerk echt meten met PowerShell

Vincent van Unen 2026-03-17
ChatGPT Image Mar 17, 2026, 09_52_02 AM
  • ESPHOME
  • Home Assistant

Slimme ESPHome multisensor: UN-SENSOR-12

Vincent van Unen 2026-03-17
ChatGPT Image Mar 13, 2026, 05_39_33 AM
  • Azure
  • Powershell

🔎 Even snel de Tenant ID van een domein ophalen met PowerShell

Vincent van Unen 2026-03-13
ChatGPT Image Mar 13, 2026, 10_06_00 AM
  • Azure
  • Powershell

Powershell : Tijdelijke toegang zonder gedoe: Temporary Access Pass automatiseren

Vincent van Unen 2026-03-13
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
Copyright © 2026 All rights reserved. | ReviewNews by AF themes.