I have built a PowerShell script for downloading files from a FTP server. This script is working with all the servers I have tested with expect one. For this one server the script is able to connect, get the directory listing, but each time it attempts to download a file a "553 File Unavailable" error is returned. Below is the code I am using to download files.
function Get-FtpFile
{
Param ([string]$fileUrl, $credentials, [string]$destination)
try
{
$FTPRequest = [System.Net.FtpWebRequest]::Create($fileUrl)
if ($credentials)
{
$FTPRequest.Credentials = $credentials
}
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$FTPRequest.UseBinary = $true
$FTPRequest.UsePassive = $true
# 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
$LocalFile = New-Object IO.FileStream ($destination,[IO.FileMode]::Create)
[byte[]]$ReadBuffer = New-Object byte[] 1024
# Loop through the download
do {
$ReadLength = $ResponseStream.Read($ReadBuffer,0,1024)
$LocalFile.Write($ReadBuffer,0,$ReadLength)
}
while ($ReadLength -ne 0)
$ResponseStream.Close()
$ReadBuffer.clear()
$LocalFile.Close()
$FTPResponse.Close()
}
catch [Net.WebException]
{
return "Unable to download because: $($_.exception)"
}
}
I have also implemented .NET tracing to debug this issue, below is one of the message blocks received when attempting to download a file.
System.Net Information: 0 : [7712] FtpWebRequest#33194379::.ctor(ftp://**.**.**.**//record/5DE7D3810004)
System.Net Information: 0 : [7712] FtpWebRequest#33194379::GetResponse(Method=RETR.)
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Created connection from 666.66.66.66:61255 to **.**.**.**:21.
System.Net Information: 0 : [7712] Associating FtpWebRequest#33194379 with FtpControlStream#18792280
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [220 FTP server ready. Username and password required]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [USER change]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [331 Password required.]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [PASS ********]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [230 Login successful. .]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [OPTS utf8 on]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [502 Command not implemented, superfluous at this site.]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [PWD]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [257 "/usr/apt/tesla/config" is the current directory.]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [TYPE I]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [200 Switching to Binary mode.]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [PASV]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [227 Entering Passive Mode (10,40,0,92,254,143)]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Sending command [RETR /record/5DE7D3810004]
System.Net Information: 0 : [7712] FtpControlStream#18792280 - Received response [553 File unavailable.]
System.Net Information: 0 : [7712] FtpWebRequest#33194379::(Releasing FTP connection#18792280.)
I have noticed that FtpWebRequest
does not CD to the directory it is downloading a file from, and instead downloads that file from the servers root directory (or any path set as the root directory). Could this be why I am encountering 553 errors? If so, is there anyway to CD to the directory you want to download files from?
While rare, indeed, some FTP servers cannot handle absolute paths with the RETR
command. One has to first CWD
to the directory and then use RETR
with file name only. FtpWebRequest
does not support that. You will have to use another FTP library.
You have asked about my WinSCP. Its .NET library does not have an explicit "change directory" request either. But it does CWD
in certain situations, so you can make it do, what you need. It particularly does CWD
before directory listing. So either you can do an explicit listing of the source directory yourself:
$session.ListDirectory("/record")
$session.GetFileToDirectory("/record/5DE7D3810004", "C:\local\path")
Or if you want to download all files anyway, you can ask for that and WinSCP will do the listing (and CWD
along) internally.
$session.GetFilesToDirectory("/record/*", "C:\local\path").Check()
Btw, WinSCP scripting has an explicit cd
command, so you can use the scripting instead, while it is not so convenient to use from PowerShell as the assembly.
Or use yet another library. For example FluentFTP has FtpClient.SetWorkingDirectory
.