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.
Tags: .NET, .NET Framework, download, FTP, FTP Download, FTP Transfer, FTP Upload, Microsoft, PowerShell, PowerShell FTP, Powershell FTP download, Powershell FTP upload, System.Net.Webclient, Upload, WebClient, Windows, Windows Powershell Last modified: August 18, 2018
Hallo,
im Abschnitt “Download File” ist die Zeile
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
enthalten. Stimmdas wirklich so?
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.
I don’t have implementet that yet… but you could use a simple try catch http://stackoverflow.com/questions/2182666/powershell-2-0-try-catch-how-to-access-the-exception
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”.
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?
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.
Thanks, I did, the first variable $Unsername is wrong ;-) Should be Username. I fixed it.
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?
Kind of confusing that your upload script uses a download method and your download script uses an upload method.
It appears that the labels are reversed. Upload is download, and download is upload. Please correct me if I’m wrong…?
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.
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
FYI, your headers are swapped. (The upload header is above the download script and vice versa)
Sorry, thanks for the mention
MANY thanks for the script – wow, saved a lot of work for me :-)
Thank you very much
Hi, great job.
The headers are still swaped and it misses $LocalFileFile.Close().
Thank you.
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.
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
Very nice, simple and useful tutorial.
Thanks
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!
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.
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.
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.
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()
well done :)
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
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
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
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
Ha nice :)
Do you have an example where you can upload multiple files from a directory to an FTP location using ASCII mode instead of binary?
How about c
connect to a ftp server,
and create a directory
then other tasks
then close this ftp connection
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
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 (“.\”)
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
Thanks for adding this :)
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.
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?
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
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
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?
Briliant for Active FTP servers
Love it
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
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?