从Powershell脚本上传多个文件

Mar*_*vel 12 powershell file-upload http multipartform-data

我有一个web应用程序,可以处理像这样的html表单的POST:

<form action="x" method="post" enctype="multipart/form-data">
  <input name="xfa" type="file">
  <input name="pdf" type="file">
  <input type="submit" value="Submit">
</form>
Run Code Online (Sandbox Code Playgroud)

请注意,有两个type="file" <input>元素.

如何从Powershell脚本编写POST脚本?我打算这样做,为服务创建一个简单的测试框架.

我找到了WebClient.UploadFile(),但只能处理单个文件.

感谢您抽出宝贵时间.

aka*_*ppi 23

我今天一直在用PowerShell制作多部分HTTP POST.我希望下面的代码对您有所帮助.

  • PowerShell本身无法进行多部分表单上传.
  • 关于它的样本也不多.我基于构建了代码.
  • 当然,Invoke-RestMethod需要PowerShell 3.0,但上面链接中后面的代码显示了如何直接使用.NET进行HTTP POST,允许您在Windows XP中运行它.

祝好运!请告诉你是否让它工作.

function Send-Results {
    param (
        [parameter(Mandatory=$True,Position=1)] [ValidateScript({ Test-Path -PathType Leaf $_ })] [String] $ResultFilePath,
        [parameter(Mandatory=$True,Position=2)] [System.URI] $ResultURL
    )
    $fileBin = [IO.File]::ReadAllBytes($ResultFilePath)
    $computer= $env:COMPUTERNAME

    # Convert byte-array to string (without changing anything)
    #
    $enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")
    $fileEnc = $enc.GetString($fileBin)

    <#
    # PowerShell does not (yet) have built-in support for making 'multipart' (i.e. binary file upload compatible)
    # form uploads. So we have to craft one...
    #
    # This is doing similar to: 
    # $ curl -i -F "file=@file.any" -F "computer=MYPC" http://url
    #
    # Boundary is anything that is guaranteed not to exist in the sent data (i.e. string long enough)
    #    
    # Note: The protocol is very precise about getting the number of line feeds correct (both CRLF or LF work).
    #>
    $boundary = [System.Guid]::NewGuid().ToString()    # 

    $LF = "`n"
    $bodyLines = (
        "--$boundary",
        "Content-Disposition: form-data; name=`"file`"$LF",   # filename= is optional
        $fileEnc,
        "--$boundary",
        "Content-Disposition: form-data; name=`"computer`"$LF",
        $computer,
        "--$boundary--$LF"
        ) -join $LF

    try {
        # Returns the response gotten from the server (we pass it on).
        #
        Invoke-RestMethod -Uri $URL -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -TimeoutSec 20 -Body $bodyLines
    }
    catch [System.Net.WebException] {
        Write-Error( "FAILED to reach '$URL': $_" )
        throw $_
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一旦我从$"backtick n"改为"backtick r backtick n",我就为我工作了 (4认同)

Mar*_*ica 6

我被这件事困扰,一直没有找到满意的解决方案。虽然这里提出的gist可以做yob,但在大文件传输的情况下效率不高。我写了一篇博客文章,为它提出了一个解决方案,基于 .NET 4.5 中存在的 HttpClient 类我的 cmdlet。如果这对您来说不是问题,您可以在以下地址查看我的解决方案http://blog.majcica.com/2016/01/13/powershell-tips-and-tricks-multipartform-data-requests/

编辑:

function Invoke-MultipartFormDataUpload
{
    [CmdletBinding()]
    PARAM
    (
        [string][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$InFile,
        [string]$ContentType,
        [Uri][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$Uri,
        [System.Management.Automation.PSCredential]$Credential
    )
    BEGIN
    {
        if (-not (Test-Path $InFile))
        {
            $errorMessage = ("File {0} missing or unable to read." -f $InFile)
            $exception =  New-Object System.Exception $errorMessage
            $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, 'MultipartFormDataUpload', ([System.Management.Automation.ErrorCategory]::InvalidArgument), $InFile
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        if (-not $ContentType)
        {
            Add-Type -AssemblyName System.Web

            $mimeType = [System.Web.MimeMapping]::GetMimeMapping($InFile)

            if ($mimeType)
            {
                $ContentType = $mimeType
            }
            else
            {
                $ContentType = "application/octet-stream"
            }
        }
    }
    PROCESS
    {
        Add-Type -AssemblyName System.Net.Http

        $httpClientHandler = New-Object System.Net.Http.HttpClientHandler

        if ($Credential)
        {
            $networkCredential = New-Object System.Net.NetworkCredential @($Credential.UserName, $Credential.Password)
            $httpClientHandler.Credentials = $networkCredential
        }

        $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler

        $packageFileStream = New-Object System.IO.FileStream @($InFile, [System.IO.FileMode]::Open)

        $contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
        $contentDispositionHeaderValue.Name = "fileData"
        $contentDispositionHeaderValue.FileName = (Split-Path $InFile -leaf)

        $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
        $streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
        $streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue $ContentType

        $content = New-Object System.Net.Http.MultipartFormDataContent
        $content.Add($streamContent)

        try
        {
            $response = $httpClient.PostAsync($Uri, $content).Result

            if (!$response.IsSuccessStatusCode)
            {
                $responseBody = $response.Content.ReadAsStringAsync().Result
                $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody

                throw [System.Net.Http.HttpRequestException] $errorMessage
            }

            $responseBody = [xml]$response.Content.ReadAsStringAsync().Result

            return $responseBody
        }
        catch [Exception]
        {
            $PSCmdlet.ThrowTerminatingError($_)
        }
        finally
        {
            if($null -ne $httpClient)
            {
                $httpClient.Dispose()
            }

            if($null -ne $response)
            {
                $response.Dispose()
            }
        }
    }
    END { }
}
Run Code Online (Sandbox Code Playgroud)

干杯