Powershell ftps upload to box.com using passive mo

2019-08-15 07:46发布

问题:

The problem:

A client requires that we upload extracted data from our system to their box.com platform, rather than our normal SFTP utility. I have box.com credentials, and am aware they require FTPS not SFTP, and require passive mode. I've cribbed a fragment from ThomasMaurer's Powershell FTP Upload and Download script. Powershell version on my server is 4.0

Code fragment is:

#config 
$Username = "username@host.com"
$Password = "redactedpassword"
$LocalFile = "C:\path\to\my\file.csv"
$RemoteFile = "ftp://ftp.box.com:990/file.csv"
#Create FTPWebRequest
$FTPRequest = [System.Net.FtpWebRequest]::Create($RemoteFile)
$FTPRequest = [System.Net.FtpWebRequest]$FTPRequest
$FTPRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$FTPRequest.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$FTPRequest.UseBinary = $true
$FTPRequest.UsePassive = $true
#read file for upload
$FileContent = gc -en byte $LocalFile
$FTPRequest.ContentLength = $FileContent.Length
#get stream request by bytes
$run = $FTPRequest.GetRequestStream()
$run.Write($FileContent,0,$FileContent.Length)
#cleanup
$run.Close()
$run.Dispose()

The error(s):

Exception calling "GetRequestStream" with "0" argument(s): "System error." At C:\path\to\my\powershellscript.ps1:28 char:1
+ $Run = $FTPRequest.GetRequestStream()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: () [], MethodInvocationException
+ FullyQualifiedErrorId: WebException

I also get downstream errors on calling the $FileContent.Length property and $run.close and $run.dispose()

Has anyone successfully automated to box (specifically) or to a passive implicit-ssl using only powershell 4.0 commands, and do you have a solid pattern I could reuse? Many thanks

回答1:

Probably too late to be useful to original questioner, but I found this other answer did the trick for me: Cyril Gupta's answer to Upload files with ftp using powershell

Here is my revised edition, including URL encoding (since the box.com usernames are email addresses which include the "at sign"):

## https://stackoverflow.com/a/2485696/537243
## User comment complains can't turn off passive mode, 
## but that is exactly what we want here!
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null

# config 
$Username = "foo@bar.com"
$Password = "s3cr3tpAssw0rd"
$Servername = "ftp.box.com"

# This is what we need URI it to look like:
#   ftp://foo%40bar.com:s3cr3tpAssw0rd@ftp.box.com/
$baseURI = "ftp://$([System.Web.HttpUtility]::UrlEncode($Username)):$([System.Web.HttpUtility]::UrlEncode($Password))@$($Servername)"

$LocalFile = "C:\tmp\to_upload\data.csv"
$RemoteFile = "date.csv"
$ftpURI = "$($baseURI)/$($RemoteFile)"

Write-output "ftp uri: $($ftpURI)";

$webclient = New-Object -TypeName System.Net.WebClient;
$ftpURI = New-Object -TypeName System.Uri -ArgumentList $ftpURI; #"convert" it
$webclient.UploadFile($ftpURI, $LocalFile);

Write-output  "Uploaded $($LocalFile) ... "; # of course since we didn't use try/catch or other error dectection this is a bit presuming.

Also should note this example uses plain FTP, not FTPS or SFTP.



回答2:

I'm uploading files with a derived version of System.Net.WebClient, which supports FTP over TLS. This can easily be achieved by embedding C# code in PowerShell:

$typeDefinition = @"
using System;
using System.Net;
public class FtpClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        FtpWebRequest ftpWebRequest = base.GetWebRequest(address) as FtpWebRequest;
        ftpWebRequest.EnableSsl = true;
        return ftpWebRequest;
    }
}
"@

Add-Type -TypeDefinition $typeDefinition
$ftpClient = New-Object FtpClient
$ftpClient.UploadFile("ftp://your-ftp-server/yourfile.name", "STOR", "C:\YourLocalFile.name")