1

I'm trying to upload a file to an ASP.NET Core API using PowerShell. My problem is that the API returns a status code 400 saying that form values are missing. Here's my PowerShell code:

add-type -AssemblyName System.Net.Http
$boundary = [System.Guid]::NewGuid().ToString()

$multipartContent = [System.Net.Http.MultipartFormDataContent]::new($boundary)
$multipartContent.Headers.Remove("Content-Type")
$multipartContent.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=`"$boundary`"")

$stringContent = [System.Net.Http.StringContent]::new("This is a file I'm uploading")
$multipartContent.Add($stringContent, "Description")

$FilePath = "c:\path\to\file.json"
$FileStream = [System.IO.File]::OpenRead($FilePath)
$streamContent = [System.Net.Http.StreamContent]::new($FileStream)
$streamContent.Headers.ContentType = "application/json"
$multipartContent.Add($streamContent, "TheFile", "file.json")

$body = $multipartContent

$response = Invoke-RestMethod 'https://myapi.com/uploadfile' -Method 'POST' -Body $body

The code is pretty much migrated from a C# sample I have and is working. Can anyone see what I am doing wrong there?

ThomasArdal
  • 4,999
  • 4
  • 33
  • 73
  • Does [this](https://stackoverflow.com/a/50255917/9164015) help? – Ash Aug 06 '21 at 08:27
  • I did try that approach actually. It generates a string that is too long. And I would like to use the code above (if possible) to make it match the C# sample I have too. – ThomasArdal Aug 06 '21 at 08:31
  • Last time I checked the Web cmdlets in PowerShell did not directly support `mutlipart/form-data` and most of the working [examples](https://gist.github.com/weipah/19bfdb14aab253e3f109) create some kind of http template for the `-Body` parameter. Your other option if you want to keep it as close as possible to the C# code you have is to use HttpClient or whatever you are currently using instead of the web cmdlets. – Ash Aug 06 '21 at 08:47
  • 1
    You're right. PowerShell doesn't support the code I'm writing. And now I got my code working with the example you provided. Thank you so much. Feel free to publish in answer and I can mark it as the right answer. I can put my code in your answer once it is created. – ThomasArdal Aug 06 '21 at 09:12

1 Answers1

2

As per my comment above, the Web cmdlets in PowerShell did not directly support mutlipart/form-data last I checked and most of the working examples create some kind of http template for the -Body parameter.

Here's a working sample:

$boundary = [System.Guid]::NewGuid().ToString()
$FilePath = "c:\path\to\file.json"
$TheFile = [System.IO.File]::ReadAllBytes($FilePath)
$TheFileContent = [System.Text.Encoding]::GetEncoding('iso-8859-1').GetString($TheFile)

$LF = "`r`n"
$bodyLines = (
    "--$boundary",
    "Content-Disposition: form-data; name=`"Description`"$LF",
    "This is a file I'm uploading",
    "--$boundary",
    "Content-Disposition: form-data; name=`"TheFile`"; filename=`"file.json`"",
    "Content-Type: application/json$LF",
    $TheFileContent,
    "--$boundary--$LF"
) -join $LF

Invoke-RestMethod 'https://myapi.com/uploadfile' -Method POST -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines

Your other option if you want to keep it as close as possible to the C# code you have is to use HttpClient or whatever you are currently using instead of the web cmdlets in PowerShell.


Update: PowerShell 7+ does include a -Form parameter on both Web Cmdlets. Please see the linked examples from the official documentation:

Ash
  • 3,030
  • 3
  • 15
  • 33