【问题标题】:PowerShell FTPS upload fails with "System error."PowerShell FTPS 上传失败并显示“系统错误”。
【发布时间】:2016-10-03 01:45:34
【问题描述】:

问题:

客户要求我们将提取的数据从我们的系统上传到他们的 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,您是否有一个可靠的模式我可以重复使用?非常感谢

【问题讨论】:

    标签: powershell ssl ftp ftpwebrequest ftps


    【解决方案1】:

    我正在上传带有派生版本System.Net.WebClient 的文件,它支持基于 TLS 的 FTP。这可以通过在 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】:

    @h0r41i0 的回答通过使用WebClient 解决了这个问题。但由于WebClient 内部使用(Ftp)WebRequest,它本身不能成为解决方案。

    我假设发生“系统错误”是因为任一 OP 都在尝试使用不安全的连接连接到安全端口 (990)。

    或者因为文件太大,OP代码试图将其全部读入内存:

    $FileContent = gc -en byte $LocalFile
    

    无论哪种情况,都没有理由放弃FtpWebRequest。只需使用安全连接 (FtpWebRequest.EnableSsl)。以及将数据从文件馈送到 FTP 流的有效方法,例如Stream.CopyTo:

    $request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.zip")
    $request.Credentials = New-Object System.Net.NetworkCredential("username", "password")
    $request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile 
    $request.EnableSsl = $True
    
    $fileStream = [System.IO.File]::OpenRead("C:\local\path\file.zip")
    $ftpStream = $request.GetRequestStream()
    
    $fileStream.CopyTo($ftpStream)
    
    $ftpStream.Dispose()
    $fileStream.Dispose()
    

    有关其他选项,请参阅Upload files with FTP using PowerShell。

    但请注意,.NET 框架不支持隐式 TLS(990 的典型用法)。只有显式 TLS。但是对显式 TLS 的支持更常见。见Does .NET FtpWebRequest Support both Implicit (FTPS) and explicit (FTPES)?

    【讨论】:

      【解决方案3】:

      可能对原始提问者有用为时已晚,但我发现这个其他答案对我有用: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。

      【讨论】:

        猜你喜欢
        • 2016-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-31
        • 1970-01-01
        • 2018-04-03
        相关资源
        最近更新 更多