PowerShell 7调用Invoke-RestMethod上传多表单文件失败,PS 5正常
问题
我通过以下PowerShell代码使用REST接口上传文件:
#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.com/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
这段代码在PowerShell 5.1中可正常运行,但在PowerShell 7中执行失败,报错信息为“Offset to Central Directory cannot be held in an Int64”。我已确认自己使用了ReadAllBytes而非ReadAllText,排除了相关帖子提到的问题,想了解PowerShell版本间的哪些变化导致了这个问题?
原因与解决方案
核心原因:PowerShell 7的编码与请求处理逻辑变化
- 字符串转字节流的默认编码改变:PowerShell 5.1中,将二进制字节通过ISO-8859-1转成字符串后,作为
Body传递时底层会按原编码转回字节流,不会丢失数据。但PowerShell 7基于.NET Core,传递字符串类型的Body时,Invoke-RestMethod会默认用UTF-8重新编码,破坏了ZIP文件的二进制结构,导致解压时出现目录偏移错误。 - HTTP请求Body的处理逻辑更严格:.NET Core将字符串类型的Body视为纯文本,不再兼容“用字符串模拟二进制流”的做法,而PowerShell 5.1的底层实现对这种场景兼容性更强。
修正方案
方案1:直接构造字节数组作为请求Body
跳过字符串转换步骤,直接拼接表单头部、文件字节和表单尾部的字节数组,确保二进制数据完整:
# 文件路径 $PathToFile = "C:\Path to file here.zip" $PackageName = Split-Path $PathToFile -Leaf # 生成表单边界 $Boundary = (New-Guid).ToString() # 构造表单头部和尾部的字节流(HTTP头用UTF-8编码) $headerBytes = [System.Text.Encoding]::UTF8.GetBytes(@" --$Boundary Content-Disposition: form-data; name="files"; filename="$PackageName" Content-Type: application/octet-stream "@) $footerBytes = [System.Text.Encoding]::UTF8.GetBytes(@" --$Boundary-- "@) # 读取文件原始字节 $fileBytes = [System.IO.File]::ReadAllBytes($PathToFile) # 合并所有部分的字节数组 $contentBody = $headerBytes + $fileBytes + $footerBytes # 构造请求参数 $Parameters = @{ Uri = "http://myUrlhere.com/TargetResource" Method = "Post" UseDefaultCredentials = $true ContentType = "multipart/form-data; boundary=`"$Boundary`"" Body = $contentBody # 直接传递字节数组 } if ($IsCoreCLR -and ($Parameters.Uri -match '^http:')) { $Parameters["AllowUnencryptedAuthentication"] = $true } # 执行上传 Invoke-RestMethod @Parameters
方案2:使用PowerShell 7+内置的-Form参数
这是更简洁可靠的方式,-Form参数会自动处理多部分表单的编码、边界和二进制数据传递,无需手动构造字节流:
$PathToFile = "C:\Path to file here.zip" $Parameters = @{ Uri = "http://myUrlhere.com/TargetResource" Method = "Post" UseDefaultCredentials = $true Form = @{ files = Get-Item $PathToFile } } if ($IsCoreCLR -and ($Parameters.Uri -match '^http:')) { $Parameters["AllowUnencryptedAuthentication"] = $true } Invoke-RestMethod @Parameters
内容的提问来源于stack exchange,提问作者Tanaka Saito
相关产品推荐
相关产品推荐

