Skip to content

Instantly share code, notes, and snippets.

@weipah
Last active March 4, 2024 22:34
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save weipah/19bfdb14aab253e3f109 to your computer and use it in GitHub Desktop.
Save weipah/19bfdb14aab253e3f109 to your computer and use it in GitHub Desktop.
PowerShell V3 Multipart/formdata example with REST-API (Invoke-RestMethod)
function Import-Portatour {
param (
[parameter(Mandatory=$True,Position=1)] [ValidateScript({ Test-Path -PathType Leaf $_ })] [String] $FilePath,
[parameter(Mandatory=$False,Position=2)] [System.URI] $ResultURL
)
# CONST
$CODEPAGE = "iso-8859-1" # alternatives are ASCII, UTF-8
# We have a REST-Endpoint
$RESTURL = "https://my.portatour.net/a/api/ImportCustomers/"
# Testing
$userEmail = "some.user@example.org"
# Read file byte-by-byte
$fileBin = [System.IO.File]::ReadAllBytes($FilePath)
# Convert byte-array to string
$enc = [System.Text.Encoding]::GetEncoding($CODEPAGE)
$fileEnc = $enc.GetString($fileBin)
# Read a second hardcoded file which we want to upload through the API call
$importConfigFileEnc = $enc.GetString([System.IO.File]::ReadAllBytes("C:\Users\xyz\Documents\WindowsPowerShell\portatour.importcfg"))
# Create Object for Credentials
$user = "Username"
$pass = "Passw0rd"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($user, $secpasswd)
# We need a boundary (something random() will do best)
$boundary = [System.Guid]::NewGuid().ToString()
# Linefeed character
$LF = "`r`n"
# Build up URI for the API-call
$uri = $RESTURL + "?userEmail=$userEmail&mode=UpdateOrInsert"
# Build Body for our form-data manually since PS does not support multipart/form-data out of the box
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"file`"; filename=`"Import.xlsx`"",
"Content-Type: application/octet-stream$LF",
$fileEnc,
"--$boundary",
"Content-Disposition: form-data; name=`"importConfig`"; filename=`"portatour.importcfg`"",
"Content-Type: application/octet-stream$LF",
$importConfigFileEnc,
"--$boundary--$LF"
) -join $LF
try {
# Submit form-data with Invoke-RestMethod-Cmdlet
Invoke-RestMethod -Uri $uri -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines -Credential $cred
}
# In case of emergency...
catch [System.Net.WebException] {
Write-Error( "REST-API-Call failed for '$URL': $_" )
throw $_
}
}
@weipah
Copy link
Author

weipah commented Mar 9, 2015

Attention: Invoke-RestMethod is only available since PowerShell 3.0 (Win8/WinSrv 2012); Win7 / 2008R2 can be updated
Initial Source: http://stackoverflow.com/questions/25075010/upload-multiple-files-from-powershell-script

  • This is the first working draft

@sujangrg
Copy link

sujangrg commented May 19, 2017

Thanks. This works perfect, at least for me :)

@Shaimaaiti
Copy link

Shaimaaiti commented Jul 2, 2017

really thanks, that helps me more

@dmichine
Copy link

dmichine commented Sep 5, 2017

Thanks, was of great help. However I did have an issue around the boundary in the header

Invoke-RestMethod -Uri $uri -Method Post -ContentType "multipart/form-data; boundary="$boundary""

I've had to remove the quotes around $boundary for it to work

Invoke-RestMethod -Uri $uri -Method POST -ContentType "multipart/form-data; boundary=$boundary"

@AndrewPla
Copy link

Thanks for sharing this gist, it definitely helped me out. This is what I came up with

   $file = "c:\file.txt"

    $fileName = Split-Path $File 
    $boundary = [guid]::NewGuid().ToString()

    $fileBin = [System.IO.File]::ReadAllBytes($File)

    $enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")

    $fileEnc = $enc.GetString($fileBin)

    $bodyLines = @(

        "--$boundary",

        "Content-Disposition: form-data; name=`"file`"; filename=`"$filename`"",

        "Content-Type: application/octet-stream$LF",

        $fileEnc,

        "--$boundary",

        "Content-Disposition: form-data; name=`"importConfig`"; filename=`"portatour.importcfg`"",

        "Content-Type: application/octet-stream$LF",

        $importConfigFileEnc,

        "--$boundary--$LF"

    ) -join $LF
      $Headers = @{
            'Authorization' = $LoginToken
        }
    $params = @{
        Uri         = $Uri
        Body        = $bodyLines
        Method      = 'Post'
        Headers     = $headers
        ContentType = "multipart/form-data; boundary=$boundary"
    }
    Invoke-RestMethod @params

`

@tjhiisager
Copy link

I still having problem with file upload, can anyone try to help me, i got this
$CurlExecutable = "C:\Delphix\curl.exe"
$CurlArguments = '-l',
$url,
'--header', """content-type: multipart/form-data""",
'--header', """Authorization: ab2aac30-91b3-4790-8fda-80970dbadf33""",
'--form', "fileFormat=@e:\Tools\Powershell\Delphix\Masking\FileFormats\BS_REC00002_CSV.FF",
'--form', "fileFormatType=DELIMITED" ,
'-s'

@(& $CurlExecutable @CurlArguments)

And thats Work, but i would like to convert it to invoke-restmethod (to get rid of curl)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment