Monitoring with PowerShell: Monitoring internet speeds

It seems like I’m having a week of requests. This one was requested by my friends at Datto. One of their clients wanted to have the ability to run speed-tests and have their RMM system generate alerts whenever the speed drops. I’ve made the following PowerShell script that uses the CLI utility from speedtest.net. This utility gives us some nice feedback to work with;

  • It returns the external IP & the internal IP for the interface used.
  • The current ISP.
  • The download and upload speed.
  • The Jitter,Latency, and packet loss of the connection.
  • and the server it uses, plus the actual speedtest.net URL so you can compare the results.

So, I’ve made the script use two different monitoring methods; one is absolute and based and the values you’ve entered. The other is a percentage based monitor that alerts if the difference between the current speedtest and the previous one is more than 20%.

The script

The script downloads the Speedtest utility from the speedtest website. You can always replace this URL with your own host if you’d like.

######### Absolute monitoring values ########## 
$maxpacketloss = 2 #how much % packetloss until we alert. 
$MinimumDownloadSpeed = 100 #What is the minimum expected download speed in Mbit/ps
$MinimumUploadSpeed = 20 #What is the minimum expected upload speed in Mbit/ps
######### End absolute monitoring values ######

#Replace the Download URL to where you've uploaded the ZIP file yourself. We will only download this file once. 
#Latest version can be found at: https://www.speedtest.net/nl/apps/cli
$DownloadURL = "https://bintray.com/ookla/download/download_file?file_path=ookla-speedtest-1.0.0-win64.zip"
$DownloadLocation = "$($Env:ProgramData)\SpeedtestCLI"
try {
    $TestDownloadLocation = Test-Path $DownloadLocation
    if (!$TestDownloadLocation) {
        new-item $DownloadLocation -ItemType Directory -force
        Invoke-WebRequest -Uri $DownloadURL -OutFile "$($DownloadLocation)\speedtest.zip"
        Expand-Archive "$($DownloadLocation)\speedtest.zip" -DestinationPath $DownloadLocation -Force
    } 
}
catch {  
    write-host "The download and extraction of SpeedtestCLI failed. Error: $($_.Exception.Message)"
    exit 1
}
$PreviousResults = if (test-path "$($DownloadLocation)\LastResults.txt") { get-content "$($DownloadLocation)\LastResults.txt" | ConvertFrom-Json }
$SpeedtestResults = & "$($DownloadLocation)\speedtest.exe" --format=json --accept-license --accept-gdpr
$SpeedtestResults | Out-File "$($DownloadLocation)\LastResults.txt" -Force
$SpeedtestResults = $SpeedtestResults | ConvertFrom-Json

#creating object
[PSCustomObject]$SpeedtestObj = @{
    downloadspeed = [math]::Round($SpeedtestResults.download.bandwidth / 1000000 * 8, 2)
    uploadspeed   = [math]::Round($SpeedtestResults.upload.bandwidth / 1000000 * 8, 2)
    packetloss    = [math]::Round($SpeedtestResults.packetLoss)
    isp           = $SpeedtestResults.isp
    ExternalIP    = $SpeedtestResults.interface.externalIp
    InternalIP    = $SpeedtestResults.interface.internalIp
    UsedServer    = $SpeedtestResults.server.host
    ResultsURL    = $SpeedtestResults.result.url
    Jitter        = [math]::Round($SpeedtestResults.ping.jitter)
    Latency       = [math]::Round($SpeedtestResults.ping.latency)
}
$SpeedtestHealth = @()
#Comparing against previous result. Alerting is download or upload differs more than 20%.
if ($PreviousResults) {
    if ($PreviousResults.download.bandwidth / $SpeedtestResults.download.bandwidth * 100 -le 80) { $SpeedtestHealth += "Download speed difference is more than 20%" }
    if ($PreviousResults.upload.bandwidth / $SpeedtestResults.upload.bandwidth * 100 -le 80) { $SpeedtestHealth += "Upload speed difference is more than 20%" }
}

#Comparing against preset variables.
if ($SpeedtestObj.downloadspeed -lt $MinimumDownloadSpeed) { $SpeedtestHealth += "Download speed is lower than $MinimumDownloadSpeed Mbit/ps" }
if ($SpeedtestObj.uploadspeed -lt $MinimumUploadSpeed) { $SpeedtestHealth += "Upload speed is lower than $MinimumUploadSpeed Mbit/ps" }
if ($SpeedtestObj.packetloss -gt $MaxPacketLoss) { $SpeedtestHealth += "Packetloss is higher than $maxpacketloss%" }

if (!$SpeedtestHealth) {
    $SpeedtestHealth = "Healthy"
}

And that is it! So this monitoring component will be uploaded to the ComStore soon. As always, Happy PowerShelling!

Kelvin Tegelaar
Follow me

12 thoughts on “Monitoring with PowerShell: Monitoring internet speeds

  1. Justin M Monk

    At line:24 char:66
    + … ts = & “$($DownloadLocation)\speedtest.exe” –format=json –accep …
    + ~~~~~~~~~~~
    Unexpected token ‘format=json’ in expression or statement.
    At line:24 char:27
    + … SpeedtestResults = & “$($DownloadLocation)\speedtest.exe” –forma …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The ‘–‘ operator works only on variables or on properties.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

    Reply
  2. Jeremiah

    So i’m getting

    + … ts = & “$($DownloadLocation)\speedtest.exe” –format=json –accep …
    + ~~~~~~~~~~~
    Unexpected token ‘format=json’ in expression or statement.

    and

    + … SpeedtestResults = & “$($DownloadLocation)\speedtest.exe” –forma …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The ‘–‘ operator works only on variables or on properties.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

    What am I missing?

    Reply
  3. Alberto Laudadio

    Hi Kelvin
    I am new with scripts in Powershell and I was trying your script, but it failed.
    I suppose that the & text in the line 24 is a typo and I deleted.
    Then I got an error in the same line: The ‘–‘ operator works only on variables or on properties.
    So I change de ” to the end of the line.
    But then the two “ConvertFrom-Json” commands failed: “Invalid JSON primitive: C.”
    Thanks in advance

    Reply
    1. Kelvin Tegelaar Post author

      Hi Tony, The post above has been updated. The previous issue was that wordpress changed line 24. Line 24 should be “$SpeedtestResults = & “$($DownloadLocation)\speedtest.exe” –format=json –accept-license –accept-gdpr”. it seems OK to me now, are you having issues?

      Reply
  4. DerekinCA

    Hello, this looks great but I am receiving this error when I try to run this script. Can you tell what might be causing this? Thank you.

    speedtest.exe : [2020-02-26 16:17:43.827] [error] Configuration – SSL connect error (UnknownException)
    At line:24 char:21
    + … stResults = & “$($DownloadLocation)\speedtest.exe” –format=json –ac …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: ([2020-02-26 16:…knownException):String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

    [2020-02-26 16:17:43.827] [error] Configuration – Cannot retrieve configuration document (0)
    [2020-02-26 16:17:43.827] [error]
    ConfigurationError – Could not retrieve or read configuration (Configuration)
    [
    2020-02-26 16:17:43.827] [error] ConfigurationError – Could not retrieve or read configuration (Configuration)
    {“type”:”log”,”timestamp”:”2020-02-27T00:17:43Z”,”message”:”Configuration – Could not retrieve or read configuration (ConfigurationError)”,”level”:”error”}

    Reply
    1. Kelvin Tegelaar Post author

      These errors come from the server you’re trying to connect to. Most likely you are either outbound blocking specific ports or you’re connecting through a proxy. You can try running the script again or selecting your own server.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.