客户要求我们将提取的数据从我们的系统上传到他们的box.com平台,而不是普通的SFTP实用程序。我有box.com凭据,我知道他们需要FTPS而不是SFTP,并且需要被动模式。我从ThomasMaurer's Powershell FTP Upload and Download script中抄了一个片段。我服务器上的Powershell版本是4.0
#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()
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
我在调用$ FileContent.Length属性和$ run.close以及$ run.dispose()
时也遇到了下游错误是否有人使用powershell 4.0命令成功自动封装(特定)或被动隐式ssl,您是否有可以重用的可靠模式?非常感谢
答案 0 :(得分:1)
对于原始提问者来说可能为时已晚,但我发现其他答案对我有用:Cyril Gupta's answer to Upload files with ftp using powershell
这是我的修订版,包括URL编码(因为box.com用户名是包含“at符号”的电子邮件地址):
## 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.
另请注意,此示例使用普通FTP,而不使用FTPS或SFTP。
答案 1 :(得分:1)
我上传的文件的派生版本为System.Net.WebClient,支持FTP over TLS。这可以通过在PowerShell中嵌入C#代码轻松实现:
$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")
答案 2 :(得分:1)
@ h0r41i0的答案通过使用AttributeError: 'module' object has no attribute 'tokenizerFunction'
解决了该问题。但是,由于WebClient
内部使用WebClient
,因此它本身并不是解决方案。
我认为发生“系统错误”是因为任一OP都试图通过不安全的连接来连接到安全端口(990)。
或者因为文件太大而OP代码试图将其全部读取到内存中:
(Ftp)WebRequest
无论哪种情况,都没有理由放弃$FileContent = gc -en byte $LocalFile
。只需使用安全连接(FtpWebRequest.EnableSsl
)。一种将数据从文件馈送到FTP流的有效方法,例如Stream.CopyTo
:
FtpWebRequest
有关其他选项,请参见Upload files with FTP using PowerShell。
尽管请注意,.NET框架不支持隐式TLS(990的典型用法)。仅显式TLS。但是,对显式TLS的支持更为常见。参见Does .NET FtpWebRequest Support both Implicit (FTPS) and explicit (FTPES)?