Uploading Packages via API

Solved Locked
SB

I'm trying to simplify the upload of Packages using the API but can't seem to get it to work.

I'm trying to code this in Powershell and a snippet of this code is below:

$MCFQDN = "SERVER.LOCATION"

Get-MobiControlToken

$response = ""
$APIURL = "https://$MCFQDN/MobiControl/api/packages"
$filename = "c:\Temp\PackageName.pcg"

$Header = @{}
$Header["Authorization"] = "Bearer " + $Token
$Header["Accept"] = "application/json"

try {
   $response = Invoke-RestMethod -Uri $APIURL -ContentType "multipart/related;" -Method POST -InFile $filename -Headers $Header
   $response
}
catch {
   $($_.Exception.Message)
}

The Get-MobiControl function works without issue, but each time I run this script I get a 415 error stating "Unsupported media type provided. Expected media type is multipart/related" but I have defined that. I've also tried defining it in the header instead. Is there something glaringly obvious I'm missing?

Thanks in advance.

Edited 6 years ago
SOTI MobiControl
ANSWERS
S
Scott
6 years ago (edited 6 years ago)

There are a number of remaining problems.  Here is a link outlining a correct MIME block:
https://stackoverflow.com/a/4656646

The request content type header needs to move from the body to the headers.  The initial multipart/related content-type is supplied as a parameter to Invoke-RestMethod: -Content-Type "multipart/related; boundary=$boundary"

In the content, $boundary needs to be on a line by itself so any time it is present it needs to be followed by $LF (and prepended with '--' )
$body = "--${boundary}${LF}"

Then each part has its own header section which needs to be terminated by a double $LF to separate it from the content:
$body += "Content-Type: application/vnd.soti.mobicontrol.package.metadata+json${LF}${LF}"

followed by the json:
$body += "{ ""DeviceFamily"": ""AndroidPlus"" }${LF}"

Add next part:
$body += "--${boundary}${LF}"

Add headers:
$body += "Content-Type: application/vnd.soti.mobicontrol.package${LF}"
$body += "Content-Type-Encoding: base64${LF}"
$body += "Content-Disposition: attachment; filename=""$filename""${LF}"
($filename should just be the filename, not the entire path)

Terminate header section:
$body += $LF

Add file content:
$body += $base64string
(I assume you correctly converted the file contents to a base64 encoded string)

Terminate MIME:
$body += "${LF}--${boundary}--${LF}"

Invoke-RestMethod automatically calculates and generates the Content-Length header so you can skip that.

ps
The example data on the API page appears to be showing a double LF between the json part and the next boundary.  I don't believe that is required according to the spec but perhaps the MC engine requires it.  You can try it both ways.

Solution
TR
Trey Rogers
3 years ago

I have found this post and am facing the same issue but Scott's answer hasn't worked for me

S
Scott
6 years ago (edited 6 years ago)

I'm not a Powershell or .Net guy but it doesn't appear to me that you can satisfy the API requirements using the base Invoke-RestMethod functionality. You are using the -InFile parameter which appears to attempt to supply the web request content from the specified file.  You are giving it your package file, which isn't web request content.  You want something closer to Example 4 of the MS help doc:

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-6

However, I don't believe even that will work as it likely makes assumptions about the construction of the content that won't match what the API requires, eg, setting content-type and inserting the package as a base64 encoded string.

You might have to resort to constructing a correctly formatted System.Net.Http.MultipartFormDataContent object and feed that to Invoke-RestMethod as the -Body parameter.

Again, I'm a perl guy so I may be missing something more straightforward but hopefully this sends you in the right direction...

ps
Found this link that might get you to what you need:
https://stackoverflow.com/a/50255917

SB
Stuart Barrett
6 years ago

Thanks for your help Scott, I've got further than where I was now, but I'm beginning to think it isn't possible in Powershell! I have tried the method from that example, however the Invoke-RestMethod command doesn't seem to have the -Form positional parameter as an option, (even after installing Powershell v6).

I've tried lots of methods now to try and deliver this file, including this one which I thought would work:

$LF = "`r`n"
$body = "Content-Type: multipart/related; boundary=$boundary" + $LF
$body += "--$boundary Content-Type: application/vnd.soti.mobicontrol.package.metadata+json" + $LF
$body += "{ ""DeviceFamily"": ""AndroidPlus"" }" + $LF
$body += "--$boundary Content-Type: application/vnd.soti.mobicontrol.package Content-Transfer-Encoding: Base64 Content-Disposition: attachment; filename=""$filename""" + $LF
$body += $base64string + " --$boundary--"
 
$response = Invoke-RestMethod -Uri $APIURL -ContentType "multipart/related; boundary=$boundary" -Method POST -Headers $Header -Body $body

Has anyone managed to upload a package to MobiControl in any programming language? The API documentation is as below and I have tried to recreate the example file in the above lines. But I always get the same error: "Unexpected end of MIME multipart stream. MIME multipart message is not complete."

API POST Package