Skip to content

Download a file with PowerShell without specifying its name

· 1 min

I’m going to show you how to download a file from the web using PowerShell without having to specify the filename on download.

This definately falls into the category of “why is this so hard in PowerShell?”. Looks like some other folks agree: github.com/PowerShell/issues/11671.

Usually you would need to use -Outfile to download a file, for example:

Terminal window
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2109047&Channel=Stable&language=en&consent=1" -Outfile "MicrosoftEdgeSetup.exe"

How does the browser know what file to give the download though?

Edge Download

Edge Download

Let’s find out:

Terminal window
$download = Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2109047&Channel=Stable&language=en&consent=1"
$download.Headers

With that we can see the name of the download:

Download

Download

To get the file name out:

Terminal window
$content = [System.Net.Mime.ContentDisposition]::new($download.Headers["Content-Disposition"])
$content

Show Filename

Show Filename

Now we could take that file name and run another Invoke-WebRequest with a -Outfile parameter, but that would involve downloading the entire file again.

Let’s save the contents of our $download variable to disk.

Terminal window
$fileName = $content.FileName
$file = [System.IO.FileStream]::new($fileName, [System.IO.FileMode]::Create)
$file.Write($download.Content, 0, $download.RawContentLength)
$file.Close()

Now we have MicrosoftEdgeSetup.exe saved.

Finally

Finally

Here is the Save-Download function which makes this process easier:

Terminal window
function Save-Download {
<#
.SYNOPSIS
Given a the result of WebResponseObject, will download the file to disk without having to specify a name.
.DESCRIPTION
Given a the result of WebResponseObject, will download the file to disk without having to specify a name.
.PARAMETER WebResponse
A WebResponseObject from running an Invoke-WebRequest on a file to download
.EXAMPLE
# Download Microsoft Edge
$download = Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2109047&Channel=Stable&language=en&consent=1"
$download | Save-Download
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline)]
[Microsoft.PowerShell.Commands.WebResponseObject]
$WebResponse,
[Parameter(Mandatory = $false)]
[string]
$Directory = "."
)
$errorMessage = "Cannot determine filename for download."
if (!($WebResponse.Headers.ContainsKey("Content-Disposition"))) {
Write-Error $errorMessage -ErrorAction Stop
}
$content = [System.Net.Mime.ContentDisposition]::new($WebResponse.Headers["Content-Disposition"])
$fileName = $content.FileName
if (!$fileName) {
Write-Error $errorMessage -ErrorAction Stop
}
if (!(Test-Path -Path $Directory)) {
New-Item -Path $Directory -ItemType Directory
}
$fullPath = Join-Path -Path $Directory -ChildPath $fileName
Write-Verbose "Downloading to $fullPath"
$file = [System.IO.FileStream]::new($fullPath, [System.IO.FileMode]::Create)
$file.Write($WebResponse.Content, 0, $WebResponse.RawContentLength)
$file.Close()
}