Reputation: 2321
I am new to PowerShell and FTP scripting, so be kind. I've searched a ton and cannot find a way to simply download a file from an FTP server using a script. I started in cmd.exe
and tried the ftp
subcommands, without success. So I switched to PowerShell (v4.0). I've seen various examples to download an FTP file, but none have worked for me. Here is my latest attempt:
$Username = "username"
$Password = "password"
$LocalFile = "C:\Users\myuser\MyFile.xlsx"
$RemoteFile = "ftp://ftp.example.com/MyFile.xlsx"
$req = [System.Net.FtpWebRequest]::Create($RemoteFile)
$req.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$req.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$req.UseBinary = $true
$req.UsePassive = $true
$req.KeepAlive = $false
# Everything works to this point.
try {
# This throws exception.
$resp = [System.Net.FtpWebResponse]$req.GetResponse()
}
catch {
$msg = $_.Exception
Write-Host "Exception: $msg" -ForegroundColor Red
}
# More code will go here later to write the data to the local file.
# Clean up.
if ($resp -ne $null) {
$resp.Close()
$resp = $null
}
The error I get is:
System.Management.Automation.MethodInvocationException: Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: 227 Entering Passive Mode (172,16,13,205,5,250).
." ---> System.Net.WebException: The remote server returned an error: 227 Entering Passive Mode (172,16,13,205,5,250).
. ---> System.Net.Sockets.SocketException: A socket operation was attempted to an unreachable network 172.16.13.205:1530
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
at System.Net.FtpControlStream.QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream, Boolean& isSocketReady)
at System.Net.FtpControlStream.PipelineCallback(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream)
at System.Net.CommandStream.PostReadCommandProcessing(Stream& stream)
at System.Net.CommandStream.ContinueCommandPipeline()
at System.Net.FtpWebRequest.TimedSubmitRequestHelper(Boolean async)
at System.Net.FtpWebRequest.SubmitRequest(Boolean async)
--- End of inner exception stack trace ---
at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
at System.Net.CommandStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetResponse()
at CallSite.Target(Closure , CallSite , Object )
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
I know the file exists and is available because when I paste ftp://username:[email protected]/MyFile.xlsx
into a browser, I get prompted to download the file, and all works fine.
The FTP server is in our network, but I want a solution that would work for FTP servers outside our network, too.
What am I doing wrong?
Upvotes: 0
Views: 6318
Reputation: 202272
The problem is a misconfigured server.
A socket operation was attempted to an unreachable network 172.16.13.205:1530
The server returned its local network IP address in the 227
response to the PASV
command.
Your client (the FtpWebRequest
) naturally cannot connect to that address and fails.
The server has to be correctly configured to know and present its external IP address in the 227
response.
Some FTP clients can overcome this misconfiguration, by either:
227
response and using the control connection address for the data transfers orEPSV
command instead of the PASV
(to which the server responds with a port number only, letting the client using the control connection address implicitly)The FtpWebRequest
cannot do either.
The Windows command-line FTP client, the ftp.exe
, does not even support the passive mode. It supports an active mode only, which can hardly work today due to ubiquitous NATs and firewalls.
For details about these kinds of problems, see my article on the FTP connection modes (active and passive).
If you cannot have the server fixed, you need to use another FTP client.
For example with WinSCP FTP/SFTP client, using its scripting interface, you can use the following batch file (.bat):
winscp.com /log=winscp.log /command ^
"open ftp://username:[email protected]" ^
"get MyFile.xlsx C:\Users\myuser\MyFile.xlsx" ^
"exit"
WinSCP ignores unroutable IP addresses in the 227
response and uses the control connection address for data transfers.
(I'm the author of WinSCP)
Upvotes: 1