In my post “Get-WeatherLinkData.ps1” I mentioned we use the free version of Paessler’s PRTG Network Monitor to monitor all we have here. It’s a great little monitoring platform, and we use it to not only keep an eye on the servers and various web-pages we run, but also track and trend our weather.

After suffering poor service from a previous ISP a few years ago, we started running a script utilising H.Merijn Brand’s Perl Speedtest CLI on our PRTG server to keep a track of speeds. It did the job but meant that Perl needed to be installed on the server.

It thus caught our eye when we saw recently that the world standard “” by Ookla has spawned an API.

And thus, New-OoklaSpeedTest.ps1 was born.

This script runs on a schedule under PRTG, captures the results of the speed test and feeds all the useful metrics into PRTG. Now we have a reliable, trustworthy report of upload and download speeds, jitter, latency and packet loss.

The API will let you specify the server to query, or you can let it decide. The server that you tested against is output by Ookla, but as PTRG won’t capture text fields, we can’t surface it in the reports.

Run with no switches, the script will display the output on screen. Add a “-filename” value and it will save the output to that file/location, overwriting any previous file of the same name.

If you have an unreliable connection, “-retries” (a value from 0 to 4) lets you make multiple attempts before reporting a failed test to PRTG.

Adding “-precision” and a number from 0-8 will report the results to that number of decimal places. (At the time of writing, the Speedtest API *also* accepts a precision value, but it doesn’t work well, reporting some badly rounded numbers like latency of 8.2870000000000008 when 3-digit precision was requested – so I’ve done the rounding in the script.)

The optional ‘-debug’ switch will save a lot more information into a monthly log file, in the format “New-OoklaSpeedTest-yyyyMMM.log”, with each entry prefaced by a timestamp:

Jul11-2230 Launched
Jul11-2230 Output file is     "W:\SCRIPTS\New-OoklaSpeedTest.ps1\test.xml"
Jul11-2230 Speedtest found at "W:\SCRIPTS\New-OoklaSpeedTest.ps1\Speedtest.exe"
Jul11-2230 Params   = "--format=json --accept-license 2>&1)"
Jul11-2231 Response = {"type":"result","timestamp":"2020-07-11T12:31:21Z","ping":{"jitter":0.53700000000000003,"latency":9.0299999999999994},"download":{"bandwidth":5980994,"bytes":38826919,"elapsed":6504},"upload":{"bandwidth":2386128,"bytes":21848868,"elapsed":9304},"packetLoss":0,"isp":"Telstra Internet","interface":{"internalIp":"","name":"","macAddr":"B4:2E:99:44:35:61","isVpn":false,"externalIp":""},"server":{"id":5744,"name":"Digital Pacific","location":"Sydney","country":"Australia","host":"","port":8080,"ip":""},"result":{"id":"4d9ba3fc-6f1c-4f89-bd7a-1b4644fbdd80","url":""}}
Jul11-2231 InternalIp   :
Jul11-2231 IsVpn        : False
Jul11-2231 ExternalIp   :
Jul11-2231 ISP          : Telstra Internet
Jul11-2231 ID           : 5744
Jul11-2231 Name         : Digital Pacific
Jul11-2231 Location     : Sydney
Jul11-2231 Country      : Australia
Jul11-2231 Host         :
Jul11-2231 IP           :
Jul11-2231 Download b/w : 5980994
Jul11-2231 Upload b/w   : 2386128
Jul11-2231 Jitter       : 0.53700000000000003
Jul11-2231 Latency      : 9.0299999999999994
Jul11-2231 Packet loss  : 0
Jul11-2231 Exited cleanly.


Add it to PRTG

Download Speedtest from Ookla and the script from Github and place them in the Custom Sensors directory on your PRTG Server (C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML). Links are at the bottom of this page.

In the PRTG console we will now create the sensor. It doesn’t really matter what device it’s attached to – you could just put it on the Probe Device. I’m going to put mine on the Internet device, which PRTG creates by default.

Click on Add Sensor and select the “EXE/Script Advanced” sensor type. Give your sensor a name and select the script from the EXE/Script dropdown.

You don’t need to add any extra parameters unless you need to enable debug or want to force a particular Speedtest server, but you will probably want to change the Scanning Interval to something greater than the default 60 seconds. I’ve chosen to run it once an hour.

Click “Create” and you are done.

If you’ve set a long scanning interval it will probably take a few minutes before the script fires and collect its first set of data. Once it has, the grey question mark will turn into a green tick. If you’re the impatient type like me, you can right-click on the sensor and select Scan Now.

It should only take a minute to refresh and show the green tick.

You can now view your data.


If you’re in the Euro-zone, you’ll need to consent to GDPR, and for that I’ve added another switch.

You’ll need to edit the sensor to add this, as shown here:

(I’ve captured the relevant terms and conditions from Ookla in the script’s header, if you’re feeling so inclined.)

Making it pretty

There’s not a lot really here that needs to change. Click on each of the channels in the Overview page and consider setting upper warning and error limits on latency, jitter and packet loss and lower warning, and error limits on upload and download speed.

Here I have set a warning if the download speed drops below 40Mb/s and an error if it drops below 20Mb/s. The later will trigger an email to prompt me to give our ISP a kick.

Scrolling down the “Edit Channel” screen, you might like to change the number of decimal places from “All” to a more manageable number. While you can set the number of decimal places in the script, if you don’t limit it in here, the averages at the top of the column end up with a lot of useless digits.

I’ll change all mine to 2 except for Packet loss. That can stay at 0.

Much neater.

Finally, scroll right down to the bottom and change the vertical axis scaling from automatic to manual.

Given that we are blessed with a 50Mb/s data service here, 50 seems like the obvious maximum for the bandwidth measurements. Hopefully setting the minimum at 0 turns out to be greatly pessimistic.

For latency and jitter, I set the maximum at 100ms and minimum 0. That should catch most peaks.

It doesn’t matter if you later change your mind on any of these settings – they only affect the rendering of the data. The data is intact so any changes made will be reflected immediately.

The end result is a nice easy to read graph of all the speedtest data. Any anomalies are obvious and if you do need to log a fault with your ISP, you have a complete history of your service.


If your speedtest sensor is throwing errors there are two ways you can peek under the hood to see what’s going wrong.


To start PRTG logging results, go back into the sensor settings and enable “Write EXE result to disk in case of error”. This will do exactly as it says on the box and create a log file of the output of the script in “C:\ProgramData\Paessler\PRTG Network Monitor\Logs\sensors”.

You might need to make a note of the sensor ID number from the main overview page if you are logging more than one sensor. Note that the log file is overwritten each time it runs.

New-OoklaSpeedTest Logs

We’ve also built logging into the script file itself. Once again, go into the sensor settings and simply add the -debug switch as a Parameter. This will create a logfile in the format “New-OoklaSpeedTest-yyyyMMM.log” in the same folder as the script itself.

This log file is continuous, starting a new log every month. As well as displaying any errors it can be useful for identifying exactly which speedtest server is being used for each test as well as all the raw data from the test.



You need to have downloaded the SpeedTest API first. It’s a simple download and doesn’t require installation. You can download it from here.


The script lives at GitHub:

Revision History

14th July 2020. Added the GDPR reference.
14th July 2020. Added troubleshooting section.
12th July 2020. This is the initial publication.

– G.


  1. Hi Greig!

    Very useful script! Have it deployed on my Internet probe and it’s working great! I was curious, if it would be possible for this script to work on a client desktop in a LAN probe?

    I would like to have this script run on client machines in my LAN and cross reference their results with what is gathered from the Internet probe. I’m not too familiar with how custom sensors work and was curious if you had any insight here.

    Thank you again for the great script!

  2. Hi Greig,

    I followed your documentation and I am getting the following error:

    “XML: The returned XML does not match the expected schema. (code: PE233) — JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)”

    Any help?


    • The answer will probably be in the PRTG logs. Enable “Write EXE result to disk in case of error” in PRTG and the check the logs in “C:\ProgramData\Paessler\PRTG Network Monitor\Logs\sensors”. It will write 2 files. You want the one “Result of Sensor xxxx.txt”.

      This shows exactly what PRTG is trying to import. It will also capture any error messages that the script may be throwing. Chances are this will tell you exactly what is going wrong.

      Let me know how you go.

    • I had the same issue. My PRTG was freshly installed only yesterday in my lab network.

      Resolution steps:

      -> Run PowerShell as administrator (PowerShell x86)
      -> Set execution policy to RemoteSigned (Set-ExecutionPolicy RemoteSigned)
      -> Verify the script can run without issues and returning values in XML format
      -> Scan now in PRTG sensor

      Greig, thanks heaps for this mate, appreciate the script and the steps in getting it running in PRTG!

      • Hi, I need help because apparently the file is working normally but PRTG is accusing the same error.

        “XML: The returned XML does not match the expected schema. (code: PE233) – JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231) ”.

        I enabled “Write EXE result to disk in case of error” but no log was generated.

        I also tried the steps below and it didn’t work:
        -> Run PowerShell as administrator (PowerShell x86)
        -> Set execution policy to RemoteSigned (Set-ExecutionPolicy RemoteSigned)
        -> Verify the script can run without issues and returning values ​​in XML format
        -> Scan now in PRTG sensor

        This was the file generated when running ps1 manually:


        • The result written to the file looks almost perfect, although I do note lots of extra spaces around the data that don’t appear when I run the script manually. I’m not sure why they would appear and if they are what’s upsetting PRTG. What Operating System and PowerShell version are you running the script on?

          I’d suggest going into the Sensor Settings and set the Result Handling to “Store result”. That way PRTG will always log the result if it thinks it’s failed or not. That may provide a clue. If the stored result also shows extra spaces, it would be worthwhile tracking down where they come from.

          • In fact it has no space, it was just the formatter that I used.

            This is the format that is presented:

            OS: Win 10
            PS Version:
            PSVersion 5.1.19041.610
            PSEdition Desktop
            PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
            BuildVersion 10.0.19041.610
            CLRVersion 4.0.30319.42000
            WSManStackVersion 3.0
            PSRemotingProtocolVersion 2.3

  3. Hello, I am experiencing the same error as David (PE231) and I followed Rocky’s recommendations.
    when I look at the log file located in “C: \ ProgramData \ Paessler \ PRTG Network Monitor \ Logs \ sensors” I read this message: “At C: \ Program Files (x86) \ PRTG Network Monitor \ custom
    sensors \ EXEXML \ New-OoklaSpeedTest.ps1: 84 char: 46
    + <meta name = "analytics-location" content = "/" & "lt; user-name" & "gt; /" & "…
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for
    future use; wrap an ampersand in double quotation marks ("&") to pass it as
    part of a string. "
    It is repeated several times.
    I followed what Shamir says but I don't know how to check "Verify the script can run without issues and returning values in XML format".
    Finally I still have the same error code.

    • Probably the easiest way to test the script is to run it in Powershell ISE. That will show you exactly what the script is sending to PRTG. Just run the PowerShell ISE app on your PRTG machine, open the script and click Run Script. You might be able to identify some odd values in the output.

      You should see the XML data with the various values for Upload Speed, Download Speed, etc. If you get an error at this point, then there’s something funky going on with the script. If you get good values in properly formatted XML then the problem is in PRTG.

      If it looks like a problem with the script, create an issue on GitHub and we’ll take it from there.

      I’ve just discovered that WordPress doesn’t like me pasting XML into comments, so it would be next to impossible to communicate properly here.

  4. Thank you for the feedback Rocky,
    I have tested the Powershell file twice. Once on the PC (W7 Pro) with PRTG and once on a PC (W10 Pro) without PRTG.
    (PS Set-ExecutionPolicy RemoteSigned)
    I had for the 2 tests the same answers below:

    W7 with PRTG :
    PS C:\Users\NG> C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\New-OoklaSpeedTest.ps1
    At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\New-OoklaSpeedTest.ps1:84 char:46
    + <meta name="analytics-location" content="/"&"lt;user-name"&"gt;/"&" …
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation
    marks ("&") to pass it as part of a string.
    At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\New-OoklaSpeedTest.ps1:84 char:61
    + C:\installation\scripts\PS\New-OoklaSpeedTest.ps1
    Au caractère C:\installation\scripts\PS\New-OoklaSpeedTest.ps1:84 : 46
    + <meta name="analytics-location" content="/"&"lt;user-name"&"gt;/"&" …
    + ~
    Le caractère perluète n’est pas autorisé. L’opérateur & est réservé à une utilisation future. Placez un caractère perluète entre
    guillemets doubles ("&") pour que ce symbole soit considéré comme une chaîne.
    Au caractère C:\installation\scripts\PS\New-OoklaSpeedTest.ps1:84 : 61
    + <meta name="analytics-location" content="/"&"lt;user-name"&"gt;/"&" …
    + ~

  5. Thanks – Very useful script. Was meaning to write one myself and then found yours. Deployed and working well.

    I have amended it to include the Server ID within the table view so I can see the server that was used for the test and just configured the channel so that its formatted correctly and not added to the chart.


  6. Many thanks ! I’ve been looking for this for a very long time!

    It seems to be a well though script and I particularly like the run options eg “-AcceptGdpr” and thank you for “-Debug” :)))

    I had some difficulties that I solved so I though I would share and help those “script enthousiast/amateur” like me.
    Note that I’m not PowerScript educated, just enough to read/understand the code (not in details) and get help from google, read logs from both PRTG and your script via -Debug

    Here is some additional info that could help :
    1- get familiar with PowerShell security (Get-ExecutionPolicy). I’ve set it to “Bypass” for Local machine
    2- check PowerScript version. v2 isn’t enough ;) – Win10 worked, Win7 (v2) needs to be updated.


  7. Is it possible to add “-attempts” option to the script like it makes up to 2 or 3 attempts and then takes a best result out of 3 attempts? I don’t mean -retries option due to unreliable connection

  8. Thank you for your PRTG input/script but I see a strange behaviour on 1 of our remote servers :

    When running a manual ookla speedtest I get download 147Mbps & upload 30,80Mbps

    When configuring the PRTG sensor with your New-OooklaSpeedTest.ps1 I get download +700Mbps and upload +35Mbps – way to much download as the link has a max of 200 Mbps download.

    How is this possible?

    • Hi Patrick,

      Good question! I’d run the script manually and see what it outputs to the screen. That might help highlight where the discrepancy is coming from.

      Alternatively, edit the sensor in PRTG to add the “-debug” switch, and then once you have some bad data, review the log file it creates (in the script’s folder) in the hope that the problem reveals itself.

      Let me know how you go with it.

      – Greig.

    • Thanks Ryan.

      The PRTG posts have encountered quite a lot of problems with people unfamiliar with GitHub saving the webpage and not the script itself.

      Our recent posts have added a detailed walk-through of the process… I think i’ll retrofit same to these earlier ones.

      – Greig.

Leave a Reply to Shamir Cancel reply

Your email address will not be published.

... and please just confirm for me that you're not a bot first: Time limit is exhausted. Please reload the CAPTCHA.

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