最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rest - Powershell 7 fails when uploading a file with Invoke-RestMethod for multipart form but works in Powershell 5 - Stack Over

programmeradmin3浏览0评论

I am uploading files to a resource using REST in the following way.

    #File names
    $PathToFile = "C:\Path to file here.zip"
    $PackageName = $(Split-Path $PathToFile -Leaf)

    #Byte stream and encoding
    $PackageByteStream = [System.IO.File]::ReadAllBytes("$PathToFile")
    $Encoding = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
    $FileEncoding = $Encoding.GetString($PackageByteStream)

    #Create the content body
    $Boundary = (New-Guid).ToString()
    $ContentBody = "--$Boundary
Content-Disposition: form-data; name=""files""; filename=""$PackageName""
Content-Type: application/octet-stream

$FileEncoding
--$Boundary--
"

    #Parameter Object
    $Parameters = @{
        Uri                   = ";
        Method                = "Post"
        UseDefaultCredentials = $true
        ContentType           = "multipart/form-data; boundary=`"$Boundary`""
        Body                  = $ContentBody
    }
    if ($IsCoreCLR -and ($Parameters.Uri -match '^http:')) {
        $Parameters += @{ "AllowUnencryptedAuthentication" = $true }
    }

    #Upload the file
    Invoke-RestMethod @Parameters

This works in Powershell 5.1 but in Powershell 7 it fails with "Offset to Central Directory cannot be held in an Int64". The only related post I could find on that was someone who used ReadAllText instead of ReadAllBytes, but since I already use ReadAllBytes I don't think it's that.

Is there something that has changed between Powershell versions that would cause this behaviour?

I am uploading files to a resource using REST in the following way.

    #File names
    $PathToFile = "C:\Path to file here.zip"
    $PackageName = $(Split-Path $PathToFile -Leaf)

    #Byte stream and encoding
    $PackageByteStream = [System.IO.File]::ReadAllBytes("$PathToFile")
    $Encoding = [System.Text.Encoding]::GetEncoding("ISO-8859-1")
    $FileEncoding = $Encoding.GetString($PackageByteStream)

    #Create the content body
    $Boundary = (New-Guid).ToString()
    $ContentBody = "--$Boundary
Content-Disposition: form-data; name=""files""; filename=""$PackageName""
Content-Type: application/octet-stream

$FileEncoding
--$Boundary--
"

    #Parameter Object
    $Parameters = @{
        Uri                   = "http://myUrlhere/TargetResource"
        Method                = "Post"
        UseDefaultCredentials = $true
        ContentType           = "multipart/form-data; boundary=`"$Boundary`""
        Body                  = $ContentBody
    }
    if ($IsCoreCLR -and ($Parameters.Uri -match '^http:')) {
        $Parameters += @{ "AllowUnencryptedAuthentication" = $true }
    }

    #Upload the file
    Invoke-RestMethod @Parameters

This works in Powershell 5.1 but in Powershell 7 it fails with "Offset to Central Directory cannot be held in an Int64". The only related post I could find on that was someone who used ReadAllText instead of ReadAllBytes, but since I already use ReadAllBytes I don't think it's that.

Is there something that has changed between Powershell versions that would cause this behaviour?

Share Improve this question asked Feb 14 at 15:30 Tanaka SaitoTanaka Saito 1,1121 gold badge24 silver badges47 bronze badges 5
  • Why not use -InFile for Pwsh 7? It's dedicated exactly to simplify this. See learn.microsoft/en-us/powershell/module/… – Santiago Squarzon Commented Feb 14 at 15:41
  • Sounds like what I need! But using that throws "Expecting a file to be uploaded". Maybe I'm misunderstanding the MS article but since I'm using -InFile I should remove the -Body parameter, set the ContentType to "application/octet-stream" since that's what the Body above uses, and use the full path to the file in -InFile. Or am I misunderstanding its use? – Tanaka Saito Commented Feb 14 at 15:53
  • Just like in this example: stackoverflow/a/42395733/15339544. So specify the path to your file in -InFile then just remove ContentType = ... (application/octet-stream is added automatically iirc) and remove Body = ... too. – Santiago Squarzon Commented Feb 14 at 15:57
  • Thank you! I tried that but now it throws "The key is invalid JQuery syntax because it is missing a closing bracket.Parameter name: key" which sounds like either the resource doesn't accept the file, or it's getting a little bit too late here and I need to get back to this on Monday. I will get back to this next week! – Tanaka Saito Commented Feb 14 at 16:20
  • @Santiago: Unfortunately, -InFile does not default to application/octet-stream; instead, the default content type solely depends on the chosen HTTP method (PUT vs. POST); see GitHub issue #24829. – mklement0 Commented Feb 14 at 17:05
Add a comment  | 

1 Answer 1

Reset to default 1

I presume you've run into the following:

  • In PowerShell (Core) 7 v7.4+, the web cmdlets (Invoke-WebRequest, Invoke-RestMethod) consistently encode text-based request bodies as UTF-8, unless explicitly specified otherwise.

  • Previously, and still in Windows PowerShell, the default was ISO-8859-1, except for JSON, which has been UTF-8-encoded since v7.0.

  • To use ISO-8859-1 encoding in v7.4+, append ; charset=iso-8859-1 to the
    -ContentType value (or, via -Headers, to the Content-Type field).

In other words, in the context of your splatted arguments:

# ...

$Parameters = @{
  Uri    = "http://myUrlhere/TargetResource"
  Method = "Post"
  UseDefaultCredentials = $true
  ContentType = "multipart/form-data; boundary=`"$Boundary`"; charset=iso-8859-1"
  Body = $ContentBody
}

# ...

Invoke-RestMethod @Parameters

Taking a step back:

  • In PowerShell 7, instead of manually constructing your multipart/form-data request body as text, consider using a streamlined approach based on a hashtable passed to the -Form parameter that references the file to upload via a Get-Item call: see example 6 of the Invoke-WebRequest help topic.

  • If you need more control over the submission, use the lower-level technique shown in example 5.

  • Note: These techniques should equally work with the Invoke-RestMethod cmdlet; Invoke-RestMethod and Invoke-WebRequest support the same parameters and differ only in the data type of their return value, reflecting their respective focus: Invoke-WebRequest is focused on HTML-page retrieval, whereas Invoke-RestMethod is focused on calling HTTP-based APIs (not only REST-ful ones); see this answer for more information.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论