我有一个JSON对象数组,我想为每个存在的对象添加一个特定的属性。
例如,数组如下:
[
{
"Average": 1.3085,
"ExtendedStatistics": {
},
"Maximum": 0,
"Minimum": 0,
"SampleCount": 0,
"Sum": 0,
"Timestamp": "\/Date(1496972280000)\/",
"Unit": {
"Value": "Percent"
}
},
{
"Average": 1.4324999999999999,
"ExtendedStatistics": {
},
"Maximum": 0,
"Minimum": 0,
"SampleCount": 0,
"Sum": 0,
"Timestamp": "\/Date(1496944680000)\/",
"Unit": {
"Value": "Percent"
}
}
]
我想添加" source":" CPU"对所有对象。我该怎么做呢?我是PowerShell的新手,并且无法完成这项任务。
答案 0 :(得分:6)
您可以执行以下操作:
$JSON | ConvertFrom-Json | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru
} | ConvertTo-Json
这假设您的JSON输入位于名为$JSON
的变量中,您需要将其替换为您访问JSON内容(例如Get-Content yourfile.json
)。
获得JSON后,我们使用ConvertFrom-JSON
将其转换为PowerShell对象。
然后我们使用管道将其发送到ForEach-Object
循环,该循环使用Add-Member
cmdlet为集合中的每个项添加属性(当前项由$_
表示)将'Source'命名为'CPU'。根据mklement0的注释,有必要使用-PassThru
开关将结果发送回管道。
然后我们将该输出传递给ConvertTo-JSON以将其转换回来。
答案 1 :(得分:5)
Mark Wragg's helpful answer效果很好,但您可能想知道为什么Add-Member
cmdlet无法直接通过管道传输,而不是需要封闭ForEach-Object
调用强>:
可以说,以下应工作,但目前(Windows PowerShell v5.1,PowerShell Core v6.1.0)不能:
# !! Currently does NOT work as expected.
$JSON | ConvertFrom-Json |
Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru
这个想法是Add-Member
直接使用管道输入,并且在修改每个输入对象之后输出它,感谢-PassThru
(默认情况下Add-Member
不产生输出)。
它不起作用的原因是当ConvertFrom-Json
输出数组时,它将输出为单个对象而不是发送正如人们所料,它的元素一个接一个地通过管道。
issue in the PowerShell GitHub repository正在讨论有问题的行为。
如果您同意这是有问题的,请在那里听到您的声音;甚至一个简单的“竖起大拇指”表明有兴趣改变它。
<强>变通方法强>:
(...)
强制枚举数组:# Enclosing the ConvertFrom-Json command in (...) forces enumeration.
($JSON | ConvertFrom-Json) |
Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru
请注意,通常,使用(...)
强制收集命令在数组中的内存中的整个输出是很方便的,但是对于大输出集可能会有问题。正如PetSerAl指出的那样,在这个的情况下,它很好,因为ConvertFrom-Json
本身无论如何都会在内存中构建整个输出数组。
Write-Output -NoEnumerate
( Windows PowerShell)/ Write-Output
(PowerShell Core ),其唯一目的是强制枚举数组元素:# Inserting Write-Output [-NoEnumerate] between ConvertFrom-Json and Add-Member
# forces enumeration of the array elements.
# *Windows PowerShell*, as of v5.1:
$JSON | ConvertFrom-Json | Write-Output -NoEnumerate |
Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru
# PowerShell *Core*:
$JSON | ConvertFrom-Json | Write-Output |
Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru
Write-Output
:Windows PowerShell :
由于错误,Write-Output
总是枚举收集本身的单个对象,即使您添加-NoEnumerate
也是如此。
矛盾的是,在这种情况下-NoEnumerate
实际上是需要 - 即使我们做想要枚举! - 以防止Write-Output
将枚举两次:一次(总是)应用于输入数组,并再次应用于各个数组元素(再次感谢PetSerAl);例如:
# !! Unexpectedly returns 4(!): enumerates the outer 2-element array
# !! *and* its elements.
# (In PowerShell *Core*, this yields 2, as expected.)
Write-Output -InputObject (1, 2), (3, 4) | Measure-Object
# BETTER: yields 2, because only the outer 2-element array is enumerated
# (In PowerShell *Core*, this yields 1, as expected.)
Write-Output -NoEnumerate -InputObject (1, 2), (3, 4) | Measure-Object
PowerShell 核心 :
以上problem has been fixed,这意味着 - 理智地 - 如果您希望-NoEnumerate
枚举自己的管道对象,那么一定不能使用Write-Output
集合(和枚举不再递归1级)。
不幸的是,引入了一个新错误:一个标量输入对象意外地包含在[PSObject[]]
数组中:
> (1 | Write-Output -NoEnumerate).GetType().Name
PSObject[]
PetSerAl报告了此错误here。