在powershell中为数组中的每个json对象添加特定属性

时间:2017-06-10 08:22:53

标签: json powershell

我有一个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的新手,并且无法完成这项任务。

2 个答案:

答案 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

的怪癖 自v5.1起

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