PowerShell Connecting to an FTP Server and Receiving Files

$ftpServer = "ftp.example.com" $username ="validUser" $password ="myPassword" $localToFTPPath = "C:\ToFTP" $localFromFTPPath = "C:\FromFTP" $remotePickupDir = "/Inbox" $remoteDropDir = "/Outbox" $SSLMode = [AlexPilotti.FTPS.Client.ESSLSupportMode]::ClearText $ftp = new-object "AlexPilotti.FTPS.Client.FTPSClient" $cred = New-Object System.Net.NetworkCredential($username,$password) $ftp.Connect($ftpServer,$cred,$SSLMode) #Connect $ftp.SetCurrentDirectory($remotePickupDir) $ftp.GetFiles($localFromFTPPath, $false) #Get Files 

This is the script I received for importing files from an FTP server.
However, I'm not sure what remotePickupDir and is this script correct?

+13
powershell ftp
source share
6 answers

The remote selection directory path must be the exact path on the ftp server you are trying to access. here is a script to download files from the server. you can add or change using SSLMode ..

 #ftp server $ftp = "ftp://example.com/" $user = "XX" $pass = "XXX" $SetType = "bin" $remotePickupDir = Get-ChildItem 'c:\test' -recurse $webclient = New-Object System.Net.WebClient $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) foreach($item in $remotePickupDir){ $uri = New-Object System.Uri($ftp+$item.Name) #$webclient.UploadFile($uri,$item.FullName) $webclient.DownloadFile($uri,$item.FullName) } 
+6
source share

The AlexFTPS library used in this question seems dead (has not been updated since 2011).


No external libraries

Alternatively, you can try to implement this without any external library. But, unfortunately, neither the .NET Framework nor PowerShell have explicit support for downloading all files in a directory (they allow only recursive file downloads).

You must implement this yourself:

  • List the remote directory
  • Repeat entries by uploading files (and possibly repeating to subdirectories - listing them again, etc.)

The challenge is to identify files from subdirectories. There is no way to do this in portable form using the .NET Framework ( FtpWebRequest or WebClient ). Unfortunately, the .NET Framework does not support the MLSD command, which is the only portable way to get a list of directories with file attributes in the FTP protocol. See also Checking whether an object on an FTP server is a file or directory .

Your options:

  • If you know that the directory does not contain any subdirectories, use the ListDirectory method ( NLST FTP command) and just upload all the "names" as files.
  • Perform an operation with a file name, which for sure will fail for the file and will succeed for directories (or vice versa). That is, you can try to download the "name".
  • You may be lucky, and in your particular case you can distinguish a file from a directory by file name (i.e. all your files have an extension, but subdirectories are not)
  • You are using a long list of directories ( LIST method = ListDirectoryDetails method) and trying to ListDirectoryDetails server-specific list. Many FTP servers use * nix-style listing, where you identify the directory by d at the very beginning of the entry. But many servers use a different format. The following example uses this approach (in * nix format)
 function DownloadFtpDirectory($url, $credentials, $localPath) { $listRequest = [Net.WebRequest]::Create($url) $listRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails $listRequest.Credentials = $credentials $lines = New-Object System.Collections.ArrayList $listResponse = $listRequest.GetResponse() $listStream = $listResponse.GetResponseStream() $listReader = New-Object System.IO.StreamReader($listStream) while (!$listReader.EndOfStream) { $line = $listReader.ReadLine() $lines.Add($line) | Out-Null } $listReader.Dispose() $listStream.Dispose() $listResponse.Dispose() foreach ($line in $lines) { $tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries) $name = $tokens[8] $permissions = $tokens[0] $localFilePath = Join-Path $localPath $name $fileUrl = ($url + $name) if ($permissions[0] -eq 'd') { if (!(Test-Path $localFilePath -PathType container)) { Write-Host "Creating directory $localFilePath" New-Item $localFilePath -Type directory | Out-Null } DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath } else { Write-Host "Downloading $fileUrl to $localFilePath" $downloadRequest = [Net.WebRequest]::Create($fileUrl) $downloadRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile $downloadRequest.Credentials = $credentials $downloadResponse = $downloadRequest.GetResponse() $sourceStream = $downloadResponse.GetResponseStream() $targetStream = [System.IO.File]::Create($localFilePath) $buffer = New-Object byte[] 10240 while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0) { $targetStream.Write($buffer, 0, $read); } $targetStream.Dispose() $sourceStream.Dispose() $downloadResponse.Dispose() } } } 

Use a function such as:

 $credentials = New-Object System.Net.NetworkCredential("user", "mypassword") $url = "ftp://ftp.example.com/directory/to/download/" DownloadFtpDirectory $url $credentials "C:\target\directory" 

Code translated from my C # example to C # Uploading all files and subdirectories via FTP .


Using a third-party library

If you want to avoid problems with parsing server-specific directory list formats, use a third-party library that supports the MLSD command and / or parses various LIST list formats. And ideally, with support for downloading all files from a directory or even recursive downloads.

For example, using the WinSCP.NET assembly, you can load the entire directory with a single call to Session.GetFiles :

 # Load WinSCP .NET assembly Add-Type -Path "WinSCPnet.dll" # Setup session options $sessionOptions = New-Object WinSCP.SessionOptions -Property @{ Protocol = [WinSCP.Protocol]::Ftp HostName = "ftp.example.com" UserName = "user" Password = "mypassword" } $session = New-Object WinSCP.Session try { # Connect $session.Open($sessionOptions) # Download files $session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check() } finally { # Disconnect, clean up $session.Dispose() } 

Internally, WinSCP uses the MLSD command, if supported by the server. Otherwise, it uses the LIST command and supports dozens of different list formats.

Session.GetFiles is the default recursive method .

(I am the author of WinSCP)

+24
source share

Here is the complete working code for downloading all files (with wildcard or file extension) from an FTP site to a local directory. Set the variable values.

  #FTP Server Information - SET VARIABLES $ftp = "ftp://XXX.com/" $user = 'UserName' $pass = 'Password' $folder = 'FTP_Folder' $target = "C:\Folder\Folder1\" #SET CREDENTIALS $credentials = new-object System.Net.NetworkCredential($user, $pass) function Get-FtpDir ($url,$credentials) { $request = [Net.WebRequest]::Create($url) $request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory if ($credentials) { $request.Credentials = $credentials } $response = $request.GetResponse() $reader = New-Object IO.StreamReader $response.GetResponseStream() while(-not $reader.EndOfStream) { $reader.ReadLine() } #$reader.ReadToEnd() $reader.Close() $response.Close() } #SET FOLDER PATH $folderPath= $ftp + "/" + $folder + "/" $files = Get-FTPDir -url $folderPath -credentials $credentials $files $webclient = New-Object System.Net.WebClient $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) $counter = 0 foreach ($file in ($files | where {$_ -like "*.txt"})){ $source=$folderPath + $file $destination = $target + $file $webclient.DownloadFile($source, $target+$file) #PRINT FILE NAME AND COUNTER $counter++ $counter $source } 
+7
source share

remotePickupDir will be the folder you want to go to the ftp server to. How "this script is correct" is good, does it work? If it works, then this is correct. If this does not work, let us know what error message or unexpected behavior you receive, and we can help you.

+1
source share

To get files / folders from FTP via powerShell, I wrote several functions, you can even get hidden things from FTP.

An example of retrieving all files that are not hidden in a specific folder:

 Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -hidden $false -File 

An example of retrieving all folders (also hidden) in a specific folder:

 Get-FtpChildItem -ftpFolderPath"ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory 

You can simply copy functions from the following module without having to install a third library: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

-one
source share

Sorry, but I found all the answers. If powershell was really understood as a shell, you would just drop your favorite reliable native ftp program and end it. A reasonable approach is to have one good tool for one specific task, which means a multifunctional operating system that offers a wide range of command line tools. MS never took this path, and it still hurts to do the most basic work. Why not replace your ecosystem with cygwin and ncftp?

-one
source share

All Articles