Use PowerShell to download a file with HTTP, HTTPS, and FTP

In PowerShell, you can download a file via HTTP, HTTPS, and FTP with the Invoke-WebRequest cmdlet

Download with SMB ^

If you are working in a hybrid IT environment, you often need to download or upload files from or to the cloud in your PowerShell scripts. If you only use Windows servers that communicate through the Server Message Block (SMB) protocol, you can simply use the Copy-Item cmdlet to copy the file from a network share:

This assumes that you have a VPN solution in place so that your cloud network virtually belongs to your intranet. Things get a bit more complicated if we are leaving the intranet and have to download from an extranet or the Internet.

Download in PowerShell 2 ^

The next simple case is where you have to download a file from the web or from an FTP server. In PowerShell 2, you had to use the New-Object cmdlet for this purpose:

As of PowerShell 3, we have the Invoke-WebRequest cmdlet, which is more convenient to work with. It is PowerShell’s counterpart to GNU wget, a popular tool in the Linux world, which is probably the reason Microsoft decided to use its name as an alias for Invoke-WebRequest. This is perhaps an understatement; Invoke-WebRequest is more powerful than wget because it allows you to not only download files but also parse them. But this is a topic for another post.

Download with Invoke-WebRequest ^

To simply download a file through HTTP, you can use this command:

In the example, we just download the HTML page that the web server at www.contoso.com generates. Note that, if you only specify the folder without the file name, as you can do with Copy-Item, PowerShell will error:

Invoke-WebRequest : Could not find a part of the path

The shorter version for the command line is:

If you omit the local path to the folder, Invoke-WebRequest will just use your current folder. The -Outfile parameter is always required if you want to save the file. The reason is that, by default, Invoke-WebRequest sends the downloaded file to the pipeline.

However, the pipeline will then not just contain the contents of the file. Instead, you will find an object with a variety of properties and methods that allow you to analyze text files. If you send a binary file through the pipeline, PowerShell will treat it as a text file and you won’t be able to use the data in the file.

To only read the contents of the text file, we need to read the Content property of the object in the pipeline:

This command does the same thing as the previous one. The -ExpandProperty parameter ensures that the header (in this case, “Content”) won’t be stored in the file.

If you want to have the file in the pipeline and store it locally, you have to use -PassThru parameter:

This command stores the web page in a file and displays the HTML code.

Download and display file

Download and display file

Authenticating at a web server ^

If the web server requires authentication, you have to use the -Credential parameter:

Note that, if you omit the -Credential parameter, PowerShell will not prompt you for a user name and password and will throw this error:

Invoke-WebRequest : Authorization Required

You have to at least pass the user name with the -Credential parameter. PowerShell will then ask for the password. If you want to avoid a dialog window in your script, you can store the credentials in a PSCredential object:

You can use the -UseDefaultCredentials parameter instead of the -Credential parameter if you want to use the credentials of the current user. To add a little extra security, you might want to encrypt the password. Make sure to always use HTTPS instead of HTTP if you have to authenticate on a remote server. If the web server uses basic authentication, your password will be transmitted in clear text if you download via HTTP.

Note that this method only works if the web server manages authentication. Nowadays, most websites use the features of a content management system (CMS) to authenticate users. Usually, you then have to fill out an HTML form. I will explain in one of my next posts how you can do this with Invoke-WebRequest.

Downloading files through FTP works analogous to HTTP. You also shouldn’t use this protocol if security matters. To download multiple files securely, you had better work with SFTP or SCP. Invoke-WebRequest doesn’t support these protocols. However, third-party PowerShell modules exist that step into the breach.

In my next post I will show you can use Invoke-WebRequest to parse HTML pages and scrape content from websites.

Join the 4sysops PowerShell group!

Your question was not answered? Ask in the forum!

9+
avataravatar
Share
67 Comments
  1. Shane 7 months ago

    Hi Michael - great article.

    I am running a script on a scheduled basis (daily) to download a .csv file. However the uri changes every month, so I was wondering if the uri destination value can be set based on a value in a reference file as opposed to hard coding it, if so how?

    Cheers

     

    0

  2. Shane 7 months ago

    Thanks Michael - worked perfectly!

    3+
    avatar
  3. Rof 6 months ago

    Hi Michael

    i am downloading a  zip file from a website using the PowerShell, however the issue  is that i have to filter by date to download that zip file.

    Thank you.

    1+

    • Author

      Is the date on the website? Then use Invoke-WebRequest to read and then adapt the script to get the right URL of the zip. Will take some coding.

      0

  4. Billy Madison 5 months ago

    Great tips, can you tell me how you would apply this same concept in powershell to download all files from a web folder? Thank you in advance.

     

    Example: https://www.foo.com/folder/*

    1+
    avatar
    • Im not sure whether this is possible. You would somehow need to enumerate the content of the folder and then download it. That is normally forbidden by webservers. 

      If you have a webserver where directory browsing is allowed, I guess you could use invoke-webrequest/invoke-restmethod to that folder which would list available files. Then you could parse the output and ask for specific files to be downloaded (or all of them). But I dont see any straight-forward way.

      0

  5. Marc@4s 1 month ago

    In case you don't want to specify the destination filename:

    If filename is part of the url, you could use

    $filename = [System.Uri]::UnescapeDataString((Split-Path -Leaf $strDownloadURL))

    (e.g. "Test%20123.pdf" --> "Test 123.pdf")

    If it's not: Use function "Get-RedirectedUrl" from https://stackoverflow.com/questions/25125818/powershell-invoke-webrequest-how-to-automatically-use-original-file-name/25127597#25127597

    0

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2020

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account