我创建了请求API并获得响应的powershell脚本,但很多时候我在JSON对象中获得没有双引号的空值,这在其他脚本中产生了错误。
如何在获得空值的地方加上双引号。
响应:
{ "Name" : {
"Tag1" : "server1",
"Tag2" : null,
"Tag3" : "web"
}
}
在这里,我期待"Tag2":"null"(需要双引号,得到空响应)
上下文: 我正在从 azure vm 获取标记,如果该特定标记不可用,则 itz 按预期返回 null。
Ex.
$webvmdata = @{
Vmtype = $wenvm.Tags.vmtype
}
$webvmdata | ConvertTo-Json
我们如何才能使用Powershell轻松处理这个问题。
提前谢谢。
注意:
- 一般来说,
null
是一个合法的 JSON 值,当 PowerShell 使用其ConvertFrom-Json
cmdlet 将 JSON 解析为自定义对象时,该值变得$null
,实际上,该 cmdlet 也内置于Invoke-RestMethod
中。
如果您确实需要在 JSON 中将null
值转换为"null"
值(即字符串),最可靠但不快速的方法是:
- 让
ConvertFrom-Json
将 JSON 解析为自定义对象... - 。然后遍历这些对象的内部结构以查找
$null
属性值并将它们替换为字符串'null'
...- 有关封装此行为的通用帮助程序函数
Edit-LeafProperty
,请参阅底部部分。
- 有关封装此行为的通用帮助程序函数
- 。并将修改后的对象转换回 JSON。
# Parse JSON into custom object(s).
$fromJson = ConvertFrom-Json @'
{
"Name": {
"Tag1": "server1",
"Tag2": null,
"Tag3": "web"
}
}
'@
# Transform the object(s) in place.
$fromJson | ForEach-Object {
# Helper script block that walks the object graph
$sb = {
foreach ($el in @($args[0])) {
if ($el -is [System.Collections.IEnumerable]) { # Nested array
foreach ($subEl in $el) { & $sb $subEl } # Recurse
}
elseif ($el -is [System.Management.Automation.PSCustomObject]) {
foreach ($prop in $el.psobject.Properties) {
# If the property value is $null, replace it with string 'null'
if ($null -eq $prop.Value) { $prop.Value = 'null' }
elseif ($prop.Value -is [System.Management.Automation.PSCustomObject]) {
& $sb $prop.Value # Recurse
}
}
}
}
}
# Call the helper script block with the input object.
& $sb $_
}
# Convert the transformed object(s) back to JSON
ConvertTo-Json $fromJson
输出(注意"null"
):
{
"Name": {
"Tag1": "server1",
"Tag2": "null",
"Tag3": "web"
}
}
单元素数组注意事项:
如果输入 JSON 是一个恰好只包含一个元素的数组 ([ ... ]
),则在 PowerShell(Core) 7+中,您需要向ConvertFrom-Json
调用添加-NoEnumerate
,以便将 JSON 解析为 PowerShell 数组 - 否则,你将只获取该元素本身,而不是包装在数组中。(这在Windows PowerShell中不是必需的)。[1]
使用广义辅助函数Edit-LeafProperty
:
如果在下面定义帮助程序函数(在运行以下代码之前),则代码将简化为以下内容:
@'
{
"Name": {
"Tag1": "server1",
"Tag2": null,
"Tag3": "web"
}
}
'@ | ConvertFrom-Json |
Edit-LeafProperty -PassThru { if ($null -eq $_.Value) { $_.Value = 'null' } } |
ConvertTo-Json
注意:
每个叶属性(一个本身不包含另一个嵌套
[pscustomobject]
的对象属性)被传递给绑定到$_
的指定脚本块({ ... }
),在那里可以根据需要检查和更新其.Value
(如果需要,.Name
)属性。-PassThru
传递每个修改的对象(修改后输出),以便结果可以直接通过管道传输到ConvertTo-Json
- 通常的警告是,输出的潜在意外截断适用:根据需要对深度超过 2 级的对象图使用
-Depth
- 请参阅这篇文章
- 通常的警告是,输出的潜在意外截断适用:根据需要对深度超过 2 级的对象图使用
PowerShell(核心)中重新保留阵列的警告与以前一样适用,但有一个额外的转折:
- 使用
ConvertFromJson -NoEnumerate
来保留(可能嵌套的)单元素数组本身。 - 由于使用了中间流式处理命令 -
Edit-LeafProperty
- 如果需要保证输出 JSON 是一个数组,即使只包含一个元素,也要使用ConvertTo-Json -AsArray
。
- 使用
请注意,该函数设计为仅处理[pscustomobject]
([System.Management.Automation.PSCustomObject
])图,例如由ConvertFrom-Json
和ConvertFrom-Csv
返回的图。
Edit-LeafProperty
源代码:
function Edit-LeafProperty {
[CmdletBinding(PositionalBinding = $false)]
param(
[Parameter(Mandatory, Position = 0)]
[scriptblock] $ScriptBlock,
[Parameter(Mandatory, ValueFromPipeline)]
[AllowNull()]
$InputObject,
[switch] $PassThru
)
begin {
# Helper script block that walks the object graph
$sb = {
foreach ($el in @($args[0])) {
if ($el -is [System.Collections.IEnumerable]) { # Nested array
foreach ($subEl in $el) { & $sb $subEl } # Recurse
}
elseif ($el -is [System.Management.Automation.PSCustomObject]) {
foreach ($prop in $el.psobject.Properties) {
if ($prop.Value -is [System.Management.Automation.PSCustomObject]) {
& $sb $prop.Value # Recurse
}
else {
# Invoke the leaf-property processing script block with
# the property at hand bound to $_
ForEach-Object $ScriptBlock -InputObject $prop
}
}
}
}
}
}
process {
& $sb $InputObject # Walk the input object at hand.
if ($PassThru) { $InputObject } # Pass it through, if requested.
}
}
[1] 请参阅此答案,了解促使这种行为变化的原因。