Search code examples
httppowershellfile-uploadmultipartform-data

Upload multiple files from Powershell script


I have a webapplication that can process POSTing of a html form like this:

<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>

Note that there are two type="file" <input> elements.

How can I script POSTing this from a Powershell script? I plan to do that to create a simple test-framework for the service.

I found WebClient.UploadFile(), but that can only handle a single file.

Thank you for taking your time.


Solution

  • I've been crafting multipart HTTP POST with PowerShell today. I hope the code below is helpful to you.

    • PowerShell itself cannot do multipart form uploads.
    • There are not many sample about it either. I built the code based on this and this.
    • Sure, Invoke-RestMethod requires PowerShell 3.0 but the code in the latter of the above links shows how to do HTTP POST with .NET directly, allowing you to have this running in Windows XP as well.

    Good luck! Please tell if you got it to work.

    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 "[email protected]" -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 $_
        }
    }