In this blog post, we will explore a PowerShell script designed to efficiently manage file downloads by measuring file sizes without requiring the actual download. By utilizing Invoke-WebRequest
, we can obtain file size information through HTTP headers, ensuring that users have accurate expectations before initiating a download. The script also compares download times using both Invoke-WebRequest
and Start-BitsTransfer
, providing valuable insights into the performance of each method. Additionally, we will implement a cleanup process for any downloaded files to maintain an organized environment.
Table of Contents
Measuring File Sizes via HTTP Headers
First we define the download URLs were making the request to. Then we create a function Get-FileSize that takes a URL as a parameter. We can use the returned object from Invoke-WebRequest
to extract the file size in the request header object. You can read about formatting numerical output here.
# download URLs $chromeUrl = "https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi" $sevenZipUrl = "https://www.7-zip.org/a/7z2408-x64.msi" function Get-FileSize { param ( $url ) # Get the sizes of the file without downloading through the returned header object $headers = Invoke-WebRequest -Uri $url -Method Head # size in bytes $sb = $headers.headers['content-length'] # 1GB, 1MB, 1KB are size constants switch ($true) { # order from largest to smallest for correct sequential conditional logic ($sb/1GB -ge 1) { $readableSize = "{0:N2} GB" -f ($sb / 1GB); break } ($sb/1MB -ge 1) { $readableSize = "{0:N2} MB" -f ($sb / 1MB); break } ($sb/1KB -ge 1) { $readableSize = "{0:N2} KB" -f ($sb / 1KB); break } default { $readableSize = "$_ Bytes"; break } } return $readableSize } $chromeSize = Get-FileSize -url $chromeUrl $sevenZSize = Get-FileSize -url $sevenZipUrl Write-Output("Chrome File size: {0}`n7-Zip File size: {1}" -f $chromeSize, $sevenZSize)
A PowerShell Function to Compare Download Times: Invoke-WebRequest vs. Start-BitsTransfer
We create a Measure-RequestTimeInMilliSeconds
function in PowerShell that allows users to efficiently compare the download times of files using both Invoke-WebRequest
and Start-BitsTransfer
. By accepting a URL and a desired file name, the function measures how long each method takes to download the specified file. It leverages the Measure-Command
cmdlet to capture the execution time in milliseconds, providing precise metrics for performance evaluation. The results are returned as a PowerShell object, making it easy to access and display the timing information. We will use this as a helper function when writing the output.
function Measure-RequestTimeInMilliSeconds { param ( $url, $fileName ) # get the file extension from the URL $fileExtension = $url.Split(".")[-1] # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/measure-command?view=powershell-7.4 $timeIWR = Measure-Command { (Invoke-WebRequest $url -OutFile "$($fileName)IWR.$fileExtension") } $timeBITS = Measure-Command { (Invoke-WebRequest $url -OutFile "$($fileName)BITS.$fileExtension") } return [psobject]@{ "iwr" = $timeIWR.TotalMilliseconds; "bits" = $timeBITS.TotalMilliseconds; } }
Displaying Download Times with a PowerShell Function for Timed Output
First, we define the Write-TimedOutput
function, which takes a URL and a name as parameters. This function calls Measure-RequestTimeInMilliSeconds
to measure the download times for both Invoke-WebRequest
and Start-BitsTransfer
. The results are then displayed, showing the time taken for each method in a clear output format. Finally, any temporary files created during the download process are removed to maintain a clean environment.
function Write-TimedOutput { param ( $url, $name ) $timedRequest = Measure-RequestTimeInMilliSeconds -url $url -fileName $name Write-Output("Time $name with Invoke-WebRequest: {0}" -f $timedRequest.iwr) Write-Output("Time $name with Start-BitsTransfer: {0}" -f $timedRequest.bits) Remove-Item -path "*.$($url.Split(".")[-1])" -Force | Out-Null } Write-TimedOutput -url $sevenZipUrl -name "7-Zip" Write-TimedOutput -url $chromeUrl -name "ChromeEnterprise"
Completed Script
$chromeUrl = "https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi" $sevenZipUrl = "https://www.7-zip.org/a/7z2408-x64.msi" function Get-FileSize { param ( $url ) $headers = Invoke-WebRequest -Uri $url -Method Head $sb = $headers.headers['content-length'] switch ($true) { ($sb/1GB -ge 1) { $readableSize = "{0:N2} GB" -f ($sb / 1GB); break } ($sb/1MB -ge 1) { $readableSize = "{0:N2} MB" -f ($sb / 1MB); break } ($sb/1KB -ge 1) { $readableSize = "{0:N2} KB" -f ($sb / 1KB); break } default { $readableSize = "$_ Bytes"; break } } return $readableSize } $chromeSize = Get-FileSize -url $chromeUrl $sevenZSize = Get-FileSize -url $sevenZipUrl Write-Output("Chrome File size: {0}`n7-Zip File size: {1}" -f $chromeSize, $sevenZSize) function Measure-RequestTimeInMilliSeconds { param ( $url, $fileName ) $fileExtension = $url.Split(".")[-1] $timeIWR = Measure-Command { (Invoke-WebRequest $url -OutFile "$($fileName)IWR.$fileExtension") } $timeBITS = Measure-Command { (Invoke-WebRequest $url -OutFile "$($fileName)BITS.$fileExtension") } return [psobject]@{ "iwr" = $timeIWR.TotalMilliseconds; "bits" = $timeBITS.TotalMilliseconds; } } function Write-TimedOutput { param ( $url, $name ) $timedRequest = Measure-RequestTimeInMilliSeconds -url $url -fileName $name Write-Output("Time $name with Invoke-WebRequest: {0}" -f $timedRequest.iwr) Write-Output("Time $name with Start-BitsTransfer: {0}" -f $timedRequest.bits) Remove-Item -path "*.$($url.Split(".")[-1])" -Force | Out-Null } Write-TimedOutput -url $sevenZipUrl -name "7-Zip" Write-TimedOutput -url $chromeUrl -name "ChromeEnterprise"
Conclusion
In this PowerShell script, we began by defining the download URLs for Google Chrome and 7-Zip. We created a function, Get-FileSize
, that retrieves and formats the file sizes without downloading them, allowing us to assess the data beforehand. Next, we implemented Measure-RequestTimeInMilliSeconds
to compare the download times using both Invoke-WebRequest
and Start-BitsTransfer
, where we found that Start-BitsTransfer
was slightly faster. Furthermore, the Background Intelligent Transfer Service (BITS) supports asynchronous transfers and can wait for system resources to become available, which is beneficial for managing larger files or slower connections. During these transfers, BITS creates temporary files in a designated directory, which are used to store partially downloaded data, ensuring that transfers can be resumed without loss of progress. Finally, the Write-TimedOutput
function displayed the download times for each method while ensuring any temporary files were cleaned up afterward. Overall, this script enhances our ability to manage file downloads efficiently, balancing speed and size considerations effectively, and it allows for running simulations to further analyze performance
Now loading...