.netpowershellftpftpwebrequest

Why does FtpWebRequest download files from the root directory? Can this cause a 553 error?


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?


Solution

  • 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.