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 |1 Answer
Reset to default 1I 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 theContent-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 aGet-Item
call: see example 6 of theInvoke-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
andInvoke-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, whereasInvoke-RestMethod
is focused on calling HTTP-based APIs (not only REST-ful ones); see this answer for more information.
-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-InFile
then just removeContentType = ...
(application/octet-stream
is added automatically iirc) and removeBody = ...
too. – Santiago Squarzon Commented Feb 14 at 15:57-InFile
does not default toapplication/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