Powershell: Uploading files with multipart/form-data
By default, when you use the -InFile
parameter of Invoke-RestMethod
Powershell will send it as application/octet-stream
. In this short article we’ll look at how to send that file with multipart/form-data
instead which is what most forms on the web use.
To send multipart/form-data
with Powershell we can use the -Form
parameter which takes a hashtable of fields and values.
I couldn’t find a service that would allow us to test file uploads for free, so in this example we’re going to use the Confluence Cloud REST API to upload an attachment to a page.
TIP: If you want to test out multipart/form-data
without file uploads httpbin has an endpoint for that: https://httpbin.org/forms/post. Just skip the authentication section and replace the url with this and the form object to reflect the fields on httpbin.
Authentication
Since we’ll be using the Confluence Cloud REST API, we must setup our authentication. Since this is not the main part i’ll show you a quick and simple way. If you want more information you can read more here: Confluence Cloud - Authentication and authorization.
Confluence REST API use Basic Authentication.
$BaseURL = "https://<your_atlassian_domain>.atlassian.net"
$credential = Get-Credential
$authString = "{0}:{1}" -f ($Credential.UserName, (ConvertFrom-SecureString $Credential.Password -AsPlainText))
$b64Encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($ConfBasicAuthString))
$headers = @{
"Authorization" = "Basic $($b64Encoded)"
"X-Atlassian-Token" = "nocheck"
"Content-Type" = "multipart/form-data"
}
This is all we need to setup before we can run request against the REST API.
Uploading an image
Confluence allows us to set three fields in our form:
- file (required)
- comment (optional)
- minorEdit (required)
So, for us to upload a file we must provide the file
field in our form object. When working with files we can use the Get-Item
cmdlet to get the file we want to upload.
$form = @{
file = Get-Item -Path $filename
minorEdit = "true"
}
This is not unique for Confluence. Web-forms that allow file upload will have a field with a type="file"
and a name="my_file"
. In your form object you would replace “file” with “my_file”.
When we have defined our form, we can submit it with Invoke-RestMethod
or Invoke-WebRequest
by setting the -Form
parameter to our $form
object.
Invoke-RestMethod -Uri "$($BaseURL)/wiki/rest/api/content/{id}/child/attachment" -Method PUT -Headers $headers -Form $form
Confluence spesific caveats
There are some configuration options that are set, but not mentioned.
Confluence itself uses XSRF when posting form-data, so to use this with the REST API we must provide the X-Atlassian-Token: nocheck
header for it to bypass it.
We also use the PUT
method instead of POST
which allows us to add a new attachment if it does not exist, or update it if it already exists.