Upload multiple files from Powershell script

后端 未结 4 1333
悲哀的现实
悲哀的现实 2020-12-01 11:17

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

4条回答
  •  自闭症患者
    2020-12-01 11:59

    I've remixed @akauppi's answer into a more generic solution, a cmdlet that:

    • Can take pipeline input from Get-ChildItem for files to upload
    • Takes an URL as a positional parameter
    • Takes a dictionary as a positional parameter, which it sends as additional form data
    • Takes an (optional) -Credential parameter
    • Takes an (optional) -FilesKey parameter to specify the formdata key for the files upload part
    • Supports -WhatIf
    • Has -Verbose logging
    • Exits with an error if something goes wrong

    It can be called like this:

    $url ="http://localhost:12345/home/upload"
    $form = @{ description = "Test 123." }
    $pwd = ConvertTo-SecureString "s3cr3t" -AsPlainText -Force
    $creds = New-Object System.Management.Automation.PSCredential ("john", $pwd)
    
    Get-ChildItem *.txt | Send-MultiPartFormToApi $url $form $creds -Verbose -WhatIf
    

    Here's the code to the full cmdlet:

    function Send-MultiPartFormToApi {
        # Attribution: [@akauppi's post](https://stackoverflow.com/a/25083745/419956)
        # Remixed in: [@jeroen's post](https://stackoverflow.com/a/41343705/419956)
        [CmdletBinding(SupportsShouldProcess = $true)] 
        param (
            [Parameter(Position = 0)]
            [string]
            $Uri,
    
            [Parameter(Position = 1)]
            [HashTable]
            $FormEntries,
    
            [Parameter(Position = 2, Mandatory = $false)]
            [System.Management.Automation.Credential()]
            [System.Management.Automation.PSCredential]
            $Credential,
    
            [Parameter(
                ParameterSetName = "FilePath",
                Mandatory = $true,
                ValueFromPipeline = $true,
                ValueFromPipelineByPropertyName = $true
            )]
            [Alias("Path")]
            [string[]]
            $FilePath,
    
            [Parameter()]
            [string]
            $FilesKey = "files"
        );
    
        begin {
            $LF = "`n"
            $boundary = [System.Guid]::NewGuid().ToString()
    
            Write-Verbose "Setting up body with boundary $boundary"
    
            $bodyArray = @()
    
            foreach ($key in $FormEntries.Keys) {
                $bodyArray += "--$boundary"
                $bodyArray += "Content-Disposition: form-data; name=`"$key`""
                $bodyArray += ""
                $bodyArray += $FormEntries.Item($key)
            }
    
            Write-Verbose "------ Composed multipart form (excl files) -----"
            Write-Verbose ""
            foreach($x in $bodyArray) { Write-Verbose "> $x"; }
            Write-Verbose ""
            Write-Verbose "------ ------------------------------------ -----"
    
            $i = 0
        }
    
        process {
            $fileName = (Split-Path -Path $FilePath -Leaf)
    
            Write-Verbose "Processing $fileName"
    
            $fileBytes = [IO.File]::ReadAllBytes($FilePath)
            $fileDataAsString = ([System.Text.Encoding]::GetEncoding("iso-8859-1")).GetString($fileBytes)
    
            $bodyArray += "--$boundary"
            $bodyArray += "Content-Disposition: form-data; name=`"$FilesKey[$i]`"; filename=`"$fileName`""
            $bodyArray += "Content-Type: application/x-msdownload"
            $bodyArray += ""
            $bodyArray += $fileDataAsString
    
            $i += 1
        }
    
        end {
            Write-Verbose "Finalizing and invoking rest method after adding $i file(s)."
    
            if ($i -eq 0) { throw "No files were provided from pipeline." }
    
            $bodyArray += "--$boundary--"
    
            $bodyLines = $bodyArray -join $LF
    
            # $bodyLines | Out-File data.txt # Uncomment for extra debugging...
    
            try {
                if (!$WhatIfPreference) {
                    Invoke-RestMethod `
                        -Uri $Uri `
                        -Method Post `
                        -ContentType "multipart/form-data; boundary=`"$boundary`"" `
                        -Credential $Credential `
                        -Body $bodyLines
                } else {
                    Write-Host "WHAT IF: Would've posted to $Uri body of length " + $bodyLines.Length
                }
            } catch [Exception] {
                throw $_ # Terminate CmdLet on this situation.
            }
    
            Write-Verbose "Finished!"
        }
    }
    

提交回复
热议问题