, , ,

PowerShell FTP upload and download

1–2 minutes
45 comments on PowerShell FTP upload and download
Windows Server FTP

A friend asked me if Powershell can do simple file up and downloads. My answer was, yes of course, very easy. So this is a post with a little information about how you can do a FTP Upload or a FTP Download using Powershell. To be clear, of course you can do much more with PowerShell and FTP. But this post should show you the basic function of FTP transfers in Powershell based on the .NET Framework. With that here is how PowerShell FTP works:

FTP Upload file using PowerShell

This is how you can upload a file using FTP with PowerShell.

# Config
$Username = "FTPUSER"
$Password = "P@assw0rd"
$LocalFile = "C:\Temp\file.zip"
$RemoteFile = "ftp://thomasmaurer.ch/downloads/files/file.zip"

# Create FTP Rquest Object
$FTPRequest = [System.Net.FtpWebRequest]::Create("$RemoteFile")
$FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$FTPRequest.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
$FTPRequest.UseBinary = $true
$FTPRequest.UsePassive = $true
# Read the File for Upload
$FileContent = gc -en byte $LocalFile
$FTPRequest.ContentLength = $FileContent.Length
# Get Stream Request by bytes
$Run = $FTPRequest.GetRequestStream()
$Run.Write($FileContent, 0, $FileContent.Length)
# Cleanup
$Run.Close()
$Run.Dispose()

FTP download file using PowerShell

And this is how you can download files from an FTP server using PowerShell.

# Config
$Username = "FTPUSER"
$Password = "P@assw0rd"
$LocalFile = "C:\Temp\file.zip"
$RemoteFile = "ftp://thomasmaurer.ch/downloads/files/file.zip"

# Create a FTPWebRequest
$FTPRequest = [System.Net.FtpWebRequest]::Create($RemoteFile)
$FTPRequest.Credentials = New-Object System.Net.NetworkCredential($Username,$Password)
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$FTPRequest.UseBinary = $true
$FTPRequest.KeepAlive = $false
# Send the ftp request
$FTPResponse = $FTPRequest.GetResponse()
# Get a download stream from the server response
$ResponseStream = $FTPResponse.GetResponseStream()
# Create the target file on the local system and the download buffer
$LocalFileFile = New-Object IO.FileStream ($LocalFile,[IO.FileMode]::Create)
[byte[]]$ReadBuffer = New-Object byte[] 1024
# Loop through the download
do {
$ReadLength = $ResponseStream.Read($ReadBuffer,0,1024)
$LocalFileFile.Write($ReadBuffer,0,$ReadLength)
}
while ($ReadLength -ne 0)

So let me know how FTP file transfers with PowerShell are working for you. Scenarios I have used this are simple automation tasks where we needed to upload or download some files.

45 responses

  1. Martin Avatar

    Hallo,
    im Abschnitt “Download File” ist die Zeile
    $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    enthalten. Stimmdas wirklich so?

  2. Rico Avatar

    Hi Thomas,

    Thanks for the great script.
    How do i implement a logic test.
    e.g. if download/upload is successfull, return ‘success’, else return ‘error’ message.

  3. Ty Moffett Avatar
    Ty Moffett

    Thanks for the information Thomas. I was wondering how you would modify your script to make it download multiple files that start with a particular name? I’d like to grab all of the files in a folder that start with “SQL”.

  4. Robert Avatar

    Hi,
    I also have same query. This script is just great, but How do I download multiple files at the same time? Any suggestion please?

  5. Forrest C. Shields II Avatar

    There is a small mistake in your code.
    On line 1 of both scripts, you define the variable $Unsername, but later on you use the variable $Username. I think you may have misspelled the first variable.

    1. Thomas Maurer Avatar

      Thanks, I did, the first variable $Unsername is wrong ;-) Should be Username. I fixed it.

  6. Paul Dietrich Avatar
    Paul Dietrich

    For some reason when i do a DownloadFile, i keep getting error 550, file unavailable. This FTP stores data is that is constantly being written to, but when i download the file through standard FTP, i do not have any issues. Is there any way to “force” the download through PowerShell whether the file is being written to or not?

  7. Ken Avatar

    Kind of confusing that your upload script uses a download method and your download script uses an upload method.

  8. Jason Avatar

    It appears that the labels are reversed. Upload is download, and download is upload. Please correct me if I’m wrong…?

  9. Jason Avatar

    After downloading the file, executing it says that another program is currently using the file. Does the fileStream, or ReadBuffer, or something need to be closed? Once I closed my PowerShell window, the file became available so something was still active, even though the script had completed.

  10. Jason Avatar

    Sorry for all the comments, but since they’re being moderated anyway :)

    Your download script is missing $LocalFileFIle.Close() to closet he stream, and release the file handle.

    Thanks!
    Jay

  11. Mike Avatar

    FYI, your headers are swapped. (The upload header is above the download script and vice versa)

    1. Thomas Maurer Avatar

      Sorry, thanks for the mention

  12. Lelala Avatar

    MANY thanks for the script – wow, saved a lot of work for me :-)
    Thank you very much

  13. Nc Avatar

    Hi, great job.

    The headers are still swaped and it misses $LocalFileFile.Close().

    Thank you.

  14. Kitt Avatar

    Perhaps I have something wrong. I have tried this using your method as well as another I found. The same thing happens in either case. I ftp a file from a local machine with a 192.168.0.0 IP. The file I retrieve is gibberish and contains foreign characters. When I use a batch file to grab the very same file, everything looks correct.

  15. Stholo Avatar

    Hey All,

    I’ve noticed that you didnt had a way to find out if upload was successfull.
    I found another method of the same class called GetFileSize. So you can simply do another request to check the remote file size and compare it with the local.

    based on your code here’s an example:

    $FTPRequest = [System.Net.FtpWebRequest]::Create(“$RemoteFile”)
    $FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
    $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::GetFileSize
    $FTPRequest.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
    $FTPRequest.UseBinary = $true
    $FTPRequest.UsePassive = $true
    $RemoteFilesize = ($FTPRequest.GetResponse()).ContentLenght

  16. Mari Avatar

    Very nice, simple and useful tutorial.
    Thanks

  17. Roland Avatar
    Roland

    Hallo, tolles Script. Funktioniert auch tadellos. Ich habe aber ein Problem mit Sonderzeichen im Dateinamen. Der Dateiname enthält das Nummernzeichen # und bei jeder Datei, die hochgeladen wird, wird der Dateiname an dieser Stelle einfach abgeschnitten. Ich habe schon versucht mit ` zu maskieren, funktioniert aber nicht.
    Hat jemand eine Idee, wie ich den kompletten Dateinamen inklusive #-Zeichen behalten kann? Wär der Hammer!
    vielen Dank!

  18. Stanislav Avatar
    Stanislav

    Thanks Thomas!
    Nice solution with Get-Content in bytes istead of annouing loops with stream!
    I noticed that you dont call .GetResponse method – it is recommended in msdn and can help to folks who wants to check status of transfer with .StatusDescription and .StatusCode.

  19. joho0 Avatar

    This code is horribly borked. The upload and download scripts are swapped and the download script isn’t complete. Use this code as a prototype, but don’t try to use it as-is. It just doesn’t work.

  20. ldusing Avatar

    I am trying to upload a file to a server, but the file size is too big. I am using…
    ‘$FileContent = [System.IO.File]::ReadAllBytes(“$LocalFile”)’ instead of …
    $FileContent = gc -en byte $LocalFile

    However, I having difficultly combining the two scripts to have the upload send in byte sizes.

    1. ldusing Avatar

      I got it to work by adding a sleep command
      $FTPRequest = [System.Net.FtpWebRequest]::Create(“$RemoteFile”)
      $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
      $FTPRequest.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
      $FTPRequest.UseBinary = $true
      $FTPRequest.UsePassive = $false
      $FileContent = [System.IO.File]::ReadAllBytes(“$LocalFile”)
      $FTPRequest.ContentLength = $FileContent.Length
      $Run = $FTPRequest.GetRequestStream()
      $Run.Write($FileContent, 0, $FileContent.Length)
      $Run.Close()
      $Run.Dispose()

  21. Andy H Avatar
    Andy H

    Hello,

    the script works fine, but I encountered strange behavior when I run the script.
    The memory usage of the powershell process consumes around 95% of the system (3.5GB) and the machine is not usable anymore.

    Is this a problem with the code or is it powershell itself?

    Thanks

  22. Lüku Avatar

    Hi Andy

    I had the same Problem use the code “$FileContent = [System.IO.File]::ReadAllBytes(“$LocalFile”)” instead of “$FileContent = gc -en byte $LocalFile”.

    ……………………….

    Danke Thomas fürs Script u Gruess us Münsingen

  23. POWERSHELLLEARNER Avatar
    POWERSHELLLEARNER

    Hi Thomas –

    I have the below script to pull data from FTP and upload it to our server.(Server name : us-apps)

    # Config
    $Username = “[email protected]”
    $Password = “password”

    #Local folder path where the file will get stored
    $LocalFile = “C:\\ProgramData\\QlikTech\\SourceDocuments\\Data\\”

    # FTP Location where the original file is stored
    $RemoteFile = “ftp.data.com///Machine Files//Exp.xlsx”

    # Create FTP Rquest Object
    $FTPRequest = [System.Net.FtpWebRequest]::Create(“$RemoteFile”)
    $FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
    $FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    $FTPRequest.Credentials = new-object System.Net.NetworkCredential($Username, $Password)
    $FTPRequest.UseBinary = $true
    $FTPRequest.UsePassive = $true

    # Read the File for Upload
    $FileContent = gc -en byte $LocalFile
    $FTPRequest.ContentLength = $FileContent.Length

    # Get Stream Request by bytes
    $Run = $FTPRequest.GetRequestStream()
    $Run.Write($FileContent, 0, $FileContent.Length)

    # Cleanup
    $Run.Close()
    $Run.Dispose()

    I am running this script in the server (us-apps) but I am getting the below error
    —————————————————————————————————-

    You cannot call a method on a null-valued expression.
    At C:\Users\Desktop\PSscript.ps1:21 char:1
    + $Run.Close()
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\Users\Desktop\PSscript.ps1:22 char:1
    + $Run.Dispose()
    + ~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    Any help is highly appreciated.

    Than you much

  24. Hemisch Avatar
    Hemisch

    Hey Thomas (Testaa)

    Needed a simple daily FTP uplad scheudle. Googled, found your site. Just copy & pasted. Works just fine!

    Thanks a lot!

    Greetings,
    Hemisch

  25. Edward Avatar

    Do you have an example where you can upload multiple files from a directory to an FTP location using ASCII mode instead of binary?

  26. mr rosh Avatar
    mr rosh

    How about c

    connect to a ftp server,

    and create a directory
    then other tasks

    then close this ftp connection

  27. Francesco Mantovani Avatar

    I keep receiving

    You cannot call a method on a null-valued expression.
    At C:\Users\franc\Desktop\FTP_Try.ps1:29 char:3
    + $ReadLength = $ResponseStream.Read($ReadBuffer,0,1024)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  28. Ranjid Singh Avatar
    Ranjid Singh

    How can I pull all files from ftp? This example does only target a specific known filename. E.g. i have to pull all XML files from a root user Folder (“.\”)

  29. satish Avatar

    This is best, just missing something for people who want to do FTPS. Below are additional parameters you need to set for FTPS. I learned it the hard way, hopefully will be helpful for someone.

    1. make sure to set TLS to 1.2 (at the beginning for the script)
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    2. enable SSL (while setting up $FTPRequest config)
    $FTPRequest.EnableSsl = $true

    1. Thomas Maurer Avatar

      Thanks for adding this :)

  30. Peter Monadjemi Avatar

    If someone like to use PowerShell Core and Get-Content you have to use -AsByteStream instead of -Encoding Byte.

    But [System.IO.File]::ReadAllBytes(“$LocalFile”) makes more sense because it might be a little faster.

  31. Binit Joshi Avatar
    Binit Joshi

    I enabled SSL as per Satish’s suggestion:

    1. make sure to set TLS to 1.2 (at the beginning for the script)
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    2. enable SSL (while setting up $FTPRequest config)
    $FTPRequest.EnableSsl = $true

    But I am getting the following error:
    Exception calling “GetResponse” with “0” argument(s): “The remote certificate is invalid according to the validation procedure.”

    Any idea? How do I add a valid certificate to my ftp server?

  32. Ralph Avatar

    When I attempt to run the download example with the only change of using known good ftp server, username, and passwordk, and local file path, I get all of the following errors. Please help.

    Exception calling “GetRequestStream” with “0” argument(s): “The remote server returned an error: (530) Not logged in.”
    At C:\Users\MyUser\Downloads\codemirror\codemirror-5.37.0\mode\powershell\PowerShell-FTP-example.ps1:18 char:1
    + $Run = $FTPRequest.GetRequestStream()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

    You cannot call a method on a null-valued expression.
    At C:\Users\MyUser\Downloads\codemirror\codemirror-5.37.0\mode\powershell\PowerShell-FTP-example.ps1:19 char:1
    + $Run.Write($FileContent, 0, $FileContent.Length)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\Users\MyUser\Downloads\codemirror\codemirror-5.37.0\mode\powershell\PowerShell-FTP-example.ps1:21 char:1
    + $Run.Close()
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\Users\MyUser\Downloads\codemirror\codemirror-5.37.0\mode\powershell\PowerShell-FTP-example.ps1:22 char:1
    + $Run.Dispose()
    + ~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  33. Saitama Avatar
    Saitama

    I tried to run the script for upload and it doesn’t work, The ftp server is Active mode.

    —————————————————————————————————————————————————-

    Exception calling “GetResponse” with “0” argument(s): “The requested URI is invalid for this FTP command.”
    At line:14 char:1
    + $RemoteFilesize = ($FTPRequest.GetResponse()).ContentLenght
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

    Exception calling “GetRequestStream” with “0” argument(s): “The requested URI is invalid for this FTP command.”
    At line:21 char:1
    + $Run = $FTPRequest.GetRequestStream()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

    You cannot call a method on a null-valued expression.
    At line:22 char:1
    + $Run.Write($FileContent, 0, $FileContent.Length)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  34. Fabian Niesen Avatar

    Hi Thomas,
    I get a Error 550 File not available if try to upload a file. Full error message (In German, sorry): Ausnahme beim Aufrufen von “GetRequestStream” mit 0 Argument(en): “Der Remoteserver hat einen Fehler zurückgegeben: (550) Datei nicht verfügbar (z.B. nicht gefunden oder kein Zugriff).”
    I have checked with FileZilla, User Creds and permissions are fine. Any Idea?

  35. Marcin Nowosiadly Avatar
    Marcin Nowosiadly

    Briliant for Active FTP servers

    Love it

  36. Chetan Avatar

    What if the source file is empty??

    I am getting below error :
    Exception calling “Write” with “3” argument(s): “Value cannot be null.
    Parameter name: buffer”
    At C:\Chetan\Powershell-Scripts\SFTPFileCheck1.10.ps1:256 char:17
    + $run.Write($filecontent, 0, $filecontent.Length)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentNullException

  37. Ashwani Avatar

    Hi Thomas,

    While running the upload script getting the below error:
    Exception calling “GetRequestStream” with “0” argument(s): “Unable to connect to the remote server”
    At D:\Level Capital Project\FTP Server Integration\psl\uploadfile.ps1:14 char:1
    + $run = $ftprequest.GetRequestStream()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

    You cannot call a method on a null-valued expression.
    At D:\Level Capital Project\FTP Server Integration\psl\uploadfile.ps1:15 char:1
    + $run.Write($filecontent, 0, $filecontent.Length)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At D:\Level Capital Project\FTP Server Integration\psl\uploadfile.ps1:16 char:1
    + $run.Close()
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At D:\Level Capital Project\FTP Server Integration\psl\uploadfile.ps1:17 char:1
    + $run.Dispose()
    + ~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Could you please confirm that what is the reason of getting that error?

  38. Manfred Mühlbacher Avatar
    Manfred Mühlbacher

    Hi Thomas,

    I tried your download script but at

    # Send the ftp request
    $FTPResponse = $FTPRequest.GetResponse()

    I get the error:
    Fehler: Ausnahme beim Aufrufen von “GetResponse” mit 0 Argument(en): “Der Remoteserver hat einen
    Fehler zurückgegeben: (550) Datei nicht verfügbar (z.B. nicht gefunden oder kein
    Zugriff).”
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,FT
    PDownloadLatestDB.ps1

    I am sure that server, username and password are correct.
    Do you have any idea what is causing the error and how to resolve it?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.