# Authors: Colleen Hutson & Geoffrey Cole
# -------------------------------------------------------------------------------------------------|
# Purpose:
# - Script is designed to test the down/up rate of a particular device
# Process:
# - Download speed is determined by downloading files increasing in size from CDN
# - Upload speed is determined by uploading files increasing in size to an S3 bucket
# - Final up/down speed rates are saved to custom WMI paths
# -------------------------------------------------------------------------------------------------|
# ------------------------------------------------ #
# Script Variables
# ------------------------------------------------ #
# Calculated download speed
$_avgDownload = 0
# Calculated upload speed
$_avgUpload = 0
# CDN address
$_cdnAddress = <CDN ADDRESS>
# S3 Bucket URL
$s3EndPoint = <S3 BUCKET ENDPOINT>
# Local file path to save downloads to
$_localDownloadPath = <LOCAL PATH TO SAVE DOWNLOADS TO>
# Track up/download failed (1=failed 0=sucess)
$_spFailureTrack = 0
# WMI Namespace
$_wmiNamespace = <CUSTOM WMI NAMESPACE>
# WMI Class
$_wmiClass = <CUSTOM WMI CLASS>
# Silence up/download progress bar, so to not throttle up/download process
$progressPreference = 'silentlyContinue'
# ------------------------------------------------ #
# First calculate the average download speed
# Download is calculated first because the files that are downloaded will be uploaded to calculate upload speed
# For Loop Logic Explanation:
# - 10 files of known size located at the CDN endpoint
# - Download, in increasing file size order, all 10 files or as many as possible 15 seconds
# ------------------------------------------------ #
# File path endings
$downloadPaths = "1_5mb", "2_5mb", "5mb", "10mb", "20mb", "25mb", "40mb", "50mb", "75mb", "100mb"
# Creates the file path for downloaded objects if it does not exist.
If (-not(Test-Path -path $_localDownloadPath)) {
New-Item $_localDownloadPath -type directory -ErrorAction SilentlyContinue | Out-Null
}
# Create lists to store download time and downloaded file sizes to
[System.Collections.ArrayList]$downloadTimes = @()
[System.Collections.ArrayList]$downloadSize = @()
try {
$index = 0
# While less than 15 seconds have elapsed and files available, download file of greater size than preceeding one
For ($startTime = Get-Date; ((Get-Date)-$startTime).TotalSeconds -le 15 -and $index -lt 10; $index++) {
# File download start time
$downStart = Get-Date
# Download file
Invoke-WebRequest $_cdnAddress/$($downloadPaths[$index]) -OutFile "$_localDownloadPath\$($downloadPaths[$index])"
# Calculate time to download file and save to list
$downloadTimes.Add(((Get-Date)-$downStart).TotalSeconds)
# Calculate size of file downloaded and save to list
$downloadSize.Add((Get-Item -Path $_localDownloadPath\$($downloadPaths[$index])).Length/1024/1024)
}
# Calcaulte average download speed
$downloadSum = 0
for ($i=0; $i -lt $downloadTimes.Count; $i++) {
$downloadSum = $downloadSum + ($downloadSize[$i] / $downloadTimes[$i] * 8)
}
$_avgDownload = $downloadSum / $downloadTimes.Count
}
catch {
$_spFailureTrack = 1
}
# ------------------------------------------------ #
# Second calculate the average upload speed
# For Loop Logic Explanation:
# - Use files that were downloaded for calculating the average download speed
# - Upload, in increasing file size order, all files that were downloaded or as many as possible 15 seconds
# ------------------------------------------------ #
try {
# Get files from SpeedTest folder and sort from smallest to largest file
$uploadPaths = Get-ChildItem $_localDownloadPath\*mb | Sort-Object -Property Length
# Create lists to store download time and downloaded file sizes to
[System.Collections.ArrayList]$uploadSize = @()
[System.Collections.ArrayList]$uploadTimes = @()
$index = 0
$index
# While less than 15 seconds have elapsed and files available, upload file of greater size than preceeding one
for ($startTime = Get-Date; ((Get-Date)-$startTime).TotalSeconds -le 15 -and $index -lt $uploadPaths.Count; $index++) {
# Start time for upload
$upStart = Get-Date
# Create S3 URL and upload file
$s3URL = "$s3EndPoint/$env:COMPUTERNAME/$($uploadPaths[$index].Name).txt"
Invoke-RestMethod -Uri $s3URL -Method Put -InFile $uploadPaths[$index].FullName
# Calculate time to upload file and save to list
$uploadTimes.Add(((Get-Date)-$upStart).TotalSeconds)
$uploadSize.Add($uploadPaths[$index].Length/1024/1024)
}
# Calculate average upload speed
$uploadSum = 0
for ($i=0; $i -lt $uploadTimes.Count; $i++) {
$uploadSum = $uploadSum + ($uploadSize[$i] / $uploadTimes[$i] * 8)
}
$_avgUpload = $uploadSum / $uploadTimes.Count
}
catch {
$_spFailureTrack = 1
}
# ------------------------------------------------ #
# Third save the up/down speeds to custom WMI Objects
# ------------------------------------------------ #
# Check if wmi namespace exists and create if not
If (Get-WmiObject -Namespace "root\cimv2" -Class "__NAMESPACE" | Where-Object { $_.Name -eq $_wmiNamespace }) {
WRITE-HOST "The root\cimv2\$_wmiNamespace WMI namespace exists."
} Else {
$wmi = [wmiclass]"root\cimv2:__Namespace"
$newNamespace = $wmi.createInstance()
$newNamespace.name = $_wmiNamespace
$newNamespace.put()
}
# WMI Class
If (Get-WmiObject -List -Namespace "root\cimv2\$_wmiNamespace" | Where-Object {$_.Name -eq $_wmiClass})
{
# The class exists, Let's clean it up.
$GetExistingInstances = Get-WmiObject -Namespace "root\cimv2\$_wmiNamespace" -Class $_wmiClass
If ($GetExistingInstances -ne $Null)
{
Remove-WMIObject -Namespace "root\cimv2\$_wmiNamespace" -Class $_wmiClass
}
}
# Publish WMI Properties
$_subClass = New-Object System.Management.ManagementClass ("root\cimv2\$_wmiNamespace", [String]::Empty, $null);
$_subClass["__CLASS"] = $_wmiClass;
$_subClass.Qualifiers.Add("Static", $true)
$_subClass.Properties.Add("Name", [System.Management.CimType]::String, $false)
$_subClass.Properties["Name"].Qualifiers.Add("Key", $true) #A key qualifier must be defined to execute 'Put' command.
$_subClass.Properties.Add("Upload", [System.Management.CimType]::Real64, $false)
$_subClass.Properties.Add("Download", [System.Management.CimType]::Real64, $false)
$_subClass.Properties.Add("SpeedTestFail", [System.Management.CimType]::Real64, $false)
$_subClass.Put()
$keyvalue = "Bandwidth"
$Filter = 'Name= "' + $keyvalue + '"'
$Inst = Get-WmiObject -Class $_wmiClass -Filter $Filter -Namespace root\cimv2\$_wmiNamespace
$Inst | Remove-WMIObject
$WMIURL = 'root\cimv2\'+$_wmiNamespace+':'+$_wmiClass
$PushDataToWMI = ([wmiclass]$WMIURL).CreateInstance()
$PushDataToWMI.Name = $keyvalue
$PushDataToWMI.Upload = $_avgUpload
$PushDataToWMI.Download = $_avgDownload
$PushDataToWMI.SpeedTestFail = $_spFailureTrack
$PushDataToWMI.Put()