HTTP Downloads in Old and New PowerShell Versions

There are primarily two ways to download files over HTTP in PowerShell: the Invoke-WebRequest cmdlet and the .NET WebClient class. They’re similar to Linux tools like wget and curl. Which one you need depends on whether you’re using older or newer PowerShell versions. In older versions, it also depends on the file’s size.

In older Posh, Invoke-WebRequest can be slow. Downloading a 1.2 GB Ubuntu ISO file took 1 hour. Downloading the same file with the WebClient class took less than 5 minutes. We tested on 5.1, the version that came out-of-box with Windows 10 Enterprise.

In newer Posh, Invoke-WebRequest performed the same as the WebClient class. We tested on 7.1 running in both Windows 10 and OS X.

If you’re downloading a small file or you’re using the latest version of Posh, use Invoke-WebRequest. We prefer this because it’s idiomatic PowerShell. Invoke-WebRequest is a built-in cmdlet. If you’re downloading a large file with the Posh that came out-of-box with Windows, you may need the WebClient class.

Digging through release notes and old documentation and some other sources didn’t lead to a point in the PowerShell history where this changed, but it may have been this port. If you know where to find the specific change, we’d love to see it!

We’ll demonstrate each way with this URL and file name:

$Url = [uri]"https://releases.ubuntu.com/20.04.3/ubuntu-20.04.3-live-server-amd64.iso"
$FileName = $Url.Segments[-1]

For details on how we got the file name and what the [uri] prefix means, check out our article on splitting URLs.

Invoke-WebRequest (Preferred Way)

Invoke-WebRequest $Url -OutFile "./$FileName"

This creates an ubuntu-20.04.3-live-server-amd64.iso file in the current directory. It shows progress while it runs.

WebClient Class (Old Way for Large Files)

Using just a file name or a file name in the ./ relative path, this downloaded to the $HOME folder. To avoid that, we constructed an absolute path using the directory of the script that ran our test code:

$LocalFilePath = Join-Path -Path $PSScriptRoot -ChildPath $FileName
(New-Object System.Net.WebClient).DownloadFile($Url, $LocalFilePath)

This creates an ubuntu-20.04.3-live-server-amd64.iso file in the same directory as the script that runs the code. It doesn’t show progress while it runs.

Happy automating!

Operating Ops

Need more than just this article? We’re available to consult.

You might also want to check out these related articles: