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

hvvq6cgz  于 2023-07-01  发布在  Shell
关注(0)|答案(2)|浏览(155)

我有一个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"
                 }
    }
]

我想补充一下“来源”:“CPU”的所有对象。我该怎么做呢?我是PowerShell的新手,还没有完成这个任务。

bq8i3lrv

bq8i3lrv1#

您可以执行以下操作:

$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”。根据mklement 0的注解,需要使用-PassThru开关将结果发送回管道。
然后,我们将该输出通过管道传输到ConvertTo-JSON以将其转换回来。

snvhrwxg

snvhrwxg2#

Mark Wragg's helpful answer运行良好,但您可能想知道**为什么Add-Member cmdlet不能通过管道 * 直接 ,而不是需要一个封闭的ForEach-Object调用*:
可以说,以下 * 应该 * 工作,但在 Windows PowerShell

# !! Does NOT work as expected in Windows PowerShell.
# OK in PowerShell (Core) 7+ 
$JSON | ConvertFrom-Json | 
  Add-Member -MemberType NoteProperty -Name 'Source' -Value 'CPU' -PassThru

其思想是Add-Member直接使用管道输入,并在修改每个输入对象后输出它,这要归功于-PassThru(默认情况下Add-Member不产生输出)。
它不起作用的原因是当Windows PowerShell的ConvertFrom-Json输出 * 数组 * 时,它将其 * 作为单个对象 * 输出,而不是像人们所期望的那样通过管道逐个发送其元素

  • PowerShell [Core] 7.0中,行为已更改,以与通常的元素枚举行为保持一致,并添加了-NoEnumerate开关作为旧行为的选择。有关导致此更改的讨论,请参见GitHub issue #3424
    解决方法
  • 使用(...),强制枚举数组:
# 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 -NoEnumerateWindows PowerShell)/的传递调用
  • just* 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* 自v5.1起**:

由于一个 bugWrite-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(Core)v6.2.3+

上面的问题已经被修复了-参见GitHub issue #5955-这意味着-明智地-如果你确实想让Write-Output枚举本身就是集合的管道对象(枚举不再递归1级),你 * 不能 * 使用-NoEnumerate

相关问题