3

I am using the following script file (ftp_test_2.ps1) to transfer files to an ftp server:

#we specify the directory where all files that we want to upload are contained 
$Dir="C:/Users/you-who/Documents/textfiles/"
#ftp server

$ftp = "ftp://192.168.100.101:21/"
$user = "aP_RDB"
$pass = "pw"
$webclient = New-Object System.Net.WebClient 
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)  

#list every txt file
foreach($item in (dir $Dir "*.txt"))
{ 
    "creating URI..."
    $uri = New-Object System.Uri($ftp+$item.Name) 
    $uri
    "attempting upload... $item"
    $webclient.UploadFile($uri, $item.FullName) 
 } 

This works fine when the $ftp is set to the local host and also connecting to another ftp test server. However, on the production ftp server, the server rejects the upload with the Powershell error:

Exception calling "UploadFile" with "2" argument(s): "The remote server returned an error: 227 Entering Passive Mode (192,168,101,99,228,67)."

At C:\Users\you-who\Documents\SandBox\ftp_test_2.ps1:17 char:24

\+$webclient.UploadFile <<<< ($uri, $item.FullName)
     \+CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
     \+ FullyQualifiedErrorId : DotNetMethodExceptionPP

On the production server there is a FileZilla server running. The messages in the server UI do not "seem" to show any errors:

(000029)2/5/2013 5:58:53 AM - (not logged in) (192.168.100.101)> USER aP_RDB
(000029)2/5/2013 5:58:53 AM - (not logged in) (192.168.100.101)> 331 Password required for ap_rdb
(000029)2/5/2013 5:58:53 AM - (not logged in) (192.168.100.101)> PASS *******
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 230 Logged on
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> OPTS utf8 on
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 200 UTF8 mode enabled
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> PWD
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 257 "/" is current directory.
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> CWD /
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 250 CWD successful. "/" is current directory.
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> TYPE I
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 200 Type set to I
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> PASV
(000029)2/5/2013 5:58:53 AM - ap_rdb (192.168.100.101)> 227 Entering Passive Mode   (192,168,101,99,228,74)
(000029)2/5/2013 5:59:14 AM - ap_rdb (192.168.100.101)> disconnected.

From my FileZilla ftp client on my laptop, I can connect and put/get files on the production ftp server IF I set the "transfer mode" to "active" (in the FileZilla client) for the connection to the production ftp server.

Since I cannot change the production server, is there a way to set the transfer mode to "active" from within Powershell somewhere in my script above? I searched the web and MS sites for help on this, but could not find anything on . Any help greatly appreciated.

-Dave Ef

Dave Ef
  • 71
  • 2
  • 5
  • 1
    use System.Net.FtpWebRequest ? see http://serverfault.com/a/253255/102464 – Loïc MICHEL Feb 05 '13 at 13:09
  • You could take a look at the ftp client powershell module here: http://gallery.technet.microsoft.com/scriptcenter/PowerShell-FTP-Client-db6fe0cb it defaults to active mode when you setup the conncetion, and is easy to use – Frode F. Feb 05 '13 at 18:04
  • @Goyuix While the answer to this question is contained in the answer to the one you linked, I'd not call this an exact duplicate as this question specifically asks about how to make an FTP connection active as opposed to passive, whereas the other just asks how to upload a file with FTP. – SpellingD Feb 06 '13 at 15:46
  • @SpellingD Thanks for chiming in on that; I am hoping others can benefit from the question and responses – Dave Ef Feb 08 '13 at 05:40
  • 1
    @Goyuix Thanks for the link; it appears that the FtpWebRequest method does provide a more robust connection method. As it turns out, the admin of the production server did get wind of the issue and did not want to have active connections required. He changed implemented a change in the ftp server setup and firewall setup, opening up a narrow range of ports for ftp connections and enabling passive connections on those ports. – Dave Ef Feb 08 '13 at 05:48

1 Answers1

5

Even though you ended up going a different route - I decided to come back and provide the answer on how to sub class WebClient and ensure that all FTP requests are "active" transfers. This requires PowerShell v2 and above to add a new type. If you need to do this in PowerShell v1, you can compile the class definition to an assembly and load it.

Also of note, you can easily expose the UseBinary property of the FtpWebRequest class in the same manner as the UsePassive property - if you need to set it as well.

$def = @"
public class ActiveFtpWebClient : System.Net.WebClient
{
  protected override System.Net.WebRequest GetWebRequest(System.Uri address)
  {
    System.Net.WebRequest request = base.GetWebRequest(address);
    if (request is System.Net.FtpWebRequest)
    {
      (request as System.Net.FtpWebRequest).UsePassive = false;
    }
    return request;
  }
}
"@

Add-Type -TypeDefinition $def
$ftp = New-Object ActiveFtpWebClient
$ftp.DownloadString("ftp://server/file.txt")
Goyuix
  • 23,614
  • 14
  • 84
  • 128