一般来说,我对使用 Invoke-RestMethod/Invoke-WebRequest 比较陌生 - 我认为这是以下问题的重要背景。
我正在调用如下电话:
$Headers = @{
"Authorization" = "Bearer {0}" -f ($token)
}
$APIUri = "https://myendpoint/information/blah"
$parameters = @{
'$expand' = 'someparams'
'$filter' = "moreparams"
}
$result = Invoke-RestMethod -Headers $headers -Uri $APIUri -Method Get -Body $parameters
但是在检查返回对象的类型时$result.GetType()
:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
我最终得到一个字符串,而不是 PSObject 或 JSON。这意味着如果不进行一些疯狂的字符串操作以将其转换为我可以使用的格式,我就无法利用这些数据。
现在,如果我像这样简单地将结果输出到 CSV 文件,数据就会正确解析:
Invoke-RestMethod -Headers $headers -Uri $APIUri -Method Get -Body $parameters -OutFile "mylocation.csv"
我可以推送到 csv,然后通过 Import-CSV
将其导入回来。但我宁愿避免采取额外的步骤,因为数据应该已经可用,并且我必须进行大量调用,这将返回许多文件。
知道这里会发生什么吗?我找到了Reddit post提到如果 JSON 或 XML 的转换失败,它会默默地返回一个字符串对象。但不确定为什么会在这种情况下发生这种情况。
编辑:发布此内容后我几乎立即意识到返回的值前面添加了意外(疯狂)的字符:
Column1,Column2,Column3
Data1,Data2,Data3
Data1,Data2,Data3
所以我猜测这些字符以某种方式杀死了转换(当我使用 ConvertTo-xxx 和 ConvertFrom-xxx 进行纠正的其他努力也被杀死时,这也是有意义的)。 但以某种方式使用 -Outfile 开关可以克服这些字符结果。
但我很好奇为什么这些字符不会引发 Outfile 开关的问题?
我可以通过.Substring()
删除这几个字符,删除字符后是否有任何简单方法将其转换为对象?
我已经使用类似下面的内容围绕这个场景进行构建,因为结果中至少内置了 newLines:
$properResult = $result.RawContent.Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries)
foreach ($line in $properResult)
$lineObject = [PSCustomObject]@{
Column1 = $line[0]
Column2 = $line[1]
Column3 = $line[2]
}
但是有点丑。任何帮助将不胜感激。
最佳答案

[1] 是 解码错误 UTF-8 BOM(Unicode 签名)的结果:
您的 Web 服务正在发送 UTF-8 数据,并在其前面添加 BOM(这并不常见;BOM 通常在文件中使用),而不是通过以下方式指示字符编码:
Content-Type
响应 header 字段中的charset
属性。在Windows PowerShell中和最高PowerShell (Core) 7.3.x:
PowerShell 不在响应数据中遵循 BOM:
- 正在修复 7.4+ 中的问题 - 请参阅 GitHub PR #19379 .
如果
Content-Type
响应 header 字段中缺少charset
属性,则默认为 ISO-8859-1 ,Windows-1252 的近乎完整的子集编码,用作英语和西欧语言环境(文化)中的 ANSI 代码页。- 此将在 7.4+ 中更改为 UTF-8(并且已在其预览版本中实现) - 请参阅 GitHub PR #18219 .
自动解析为
Invoke-RestMethod
的对象执行仅限于:XML 媒体类型:
application/xml
被解析为单个[xml]
实例。application/rss+xml
和application/atom+xml
被解析为XmlElement
的集合实例
JSON(
application/json
):- 被解析为
[pscustomobject]
图表(或其数组)。
- 被解析为
任何其他媒体类型,包括 CSV 数据 (
text/csv
),都会简单地以字符串数据 ([string]
)从 PowerShell 7.3.3 开始,我不知道有计划添加对其他媒体类型的自动解析支持。
结果是:
您的问题可能会在 PowerShell v7.4+ 中消失
如果您可以控制网络服务,则也可以通过使响应在
Content 中包含
header 字段;例如,charset=utf-8
属性来修复早期版本中的问题-Typetext/plain; charset=utf-8
,并发送不带 BOM 的数据。否则,您需要解决方法:
使用
-OutFile
将数据写入(临时)文件是一种可行的解决方法:- PowerShell 将原始字节写入文件,并且当 PowerShell 从文件读取时,会遵循 BOM。
内存中解决方法需要更多工作:您必须使用
Invoke-WebRequest
而不是Invoke-RestMethod
,它使您可以访问响应数据的原始字节,然后您可以将其手动解码为UTF-8,然后使用ConvertFrom-Csv
进行解析:
# ...
# Note: Use Invoke-*WebRequest*
$result = Invoke-WebRequest -Headers $headers -Uri $APIUri -Method Get -Body $parameters
# Decode the raw result data as UTF-8 and skip the BOM with .Substring(1)
# (A *decoded* BOM is a *single* Unicode character; if your response
# truly has *two* BOMs, use .Substring(2)
$stringDecodedAsUtf8 =
[Text.Encoding]::UTF8.GetString(
$result.RawContentStream.ToArray()
).Substring(1)
# Now you can parse the correctly decoded string data as CSV.
$stringDecodedAsUtf8 | ConvertFrom-CsvData
[1] 如果此序列确实在数据开头出现两次,即使正确解释为 BOM 前缀的 UTF-8,您最终也会得到 - 通常 < em>隐形 - U+FEFF
) 字符(ZERO WIDTH NO-BREAK SPACE)位于解码数据的开头。
事实上,BOM 字节序列是所指示的编码中该字符的编码。也就是说,虽然它本身就是一个字符,但它也充当 BOM,但仅位于数据的最开头。
具体而言,
是以下 U+FEFF
错误解码的结果:
[Text.Encoding]::GetEncoding('iso-8859-1').GetString([Text.Encoding]::UTF8.GetBytes([char] 0xFEFF))
关于powershell - Invoke-RestMethod(或 Invoke-WebRequest)返回字符串而不是 PS 对象或 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75959914/