Powershell从多个文件创建对象

时间:2016-12-09 18:08:06

标签: powershell pscustomobject

我正在从json文件制作PSObject

bar.json

{
  "derp": {
   "buzz": 42 
   },
   "woot":  {
     "toot": 9000
   }
}

我可以使用ConvertFrom-Json

创建一个PSCustomObject形式的json
$foo = Get-Content .\bar.json -Raw |ConvertFrom-Json
$foo.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

但是,如果我尝试splat多个json文件,我会得到一个数组

$foo = Get-Content .\*.json -Raw |ConvertFrom-Json
$foo.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    Object[]                                 System.Array

为了迭代$ foo,我需要2个不同的代码路径,具体取决于对象类型。

我可以从多个json文件中获取单个对象吗? 如果没有,我如何将一组对象压缩成一个对象?

我尝试制作一个包含$bar

所有数组项的新对象$foo
$bar = new-object psobject
$bar | add-member -name $foo[0].psobject.properties.name -value $foo[0].'derp' -memberType NoteProperty

更新
根据Walter Mitty的要求。如果我加载单个文件并运行$foo[0]

$foo = Get-Content .\bar.json -Raw |ConvertFrom-Json
$foo[0].gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

$foo[0]

derp                                                    woot
------------                                            ------------
@{Provisioners=System.Object[]; OS=windows; Size=; V... @{Provisioners=System.Object[]; OS=windows; Size=; V...

解决方案

我最初实现了AP的答案,但后来重构了它以使用mklement0的答案。

虽然$ allObjects是一个数组,但它仍然允许我按名称引用值,这正是我所寻找的

$allObjects = @(
    Get-ChildItem '.\foo' -Filter *.json -Recurse | Get-Content -Raw | ConvertFrom-Json
)

# iterating over nested objects inside an array is hard.
# make it easier by moving all array objects into 1 parent object where 
# the 'key' is the name (opposed to AP's answer where filename = key)
$newObject = New-Object PSObject
foreach ($i in $allObjects) {
    $i.psobject.members | ?{$_.Membertype -eq 'noteproperty'} |%{$newObject | add-member $_.Name $_.Value}
}

2 个答案:

答案 0 :(得分:2)

如果你想要的只是一个从不同文件中解析出来的JSON对象数组:

$final = @{}

# Loop Thru All JSON Files, and add to $Final[<name>] = <JSON>
ls .\*.json | % {
  $o = cat $_ -Raw | ConvertFrom-Json
  $final[$_.name] = [PsCustomObject]$o
}
$final = [PsCustomObject]$final

这将生成名称 - &gt;所有JSON文件的数据映射为嵌套PSObject

答案 1 :(得分:1)

AP.'s helpful answer是创建单个顶级对象([pscustomobject]实例)的优雅解决方案:

  • 将所有JSON转换的对象包含为为其输入文件名命名的属性。

    • 例如,$final将包含bar.json属性,其值是与问题中的JSON字符串等效的对象。

    • 需要注意的是,如果文件名重复,则处理的最后一个文件将会#34; win&#34;。

有关使用说明的详细信息,请参阅底部的Unix样式别名lscat

获取所有已转换的JSON对象的数组 ,以下就足够了:

$allObjects = @(Get-ChildItem -Filter *.json | Get-Content -Raw | ConvertFrom-Json)

请注意,如果您只需要单个目录的JSON文件, $allObjects = @(Get-Content -Path *.json -Raw | ConvertFrom-Json)也有效。

请注意使用@(...) 数组子表达式运算符,它确保将返回的内容视为数组,即使只是 >返回单个对象。

  • 默认情况下,或者使用$(...) 常规子表达式运算符时,PowerShell会解包所有(可能是嵌套的)单项集合,并仅返回项目本身;见Get-Help about_Operators

关于PowerShell的lscat cmdlet使用Unix样式别名Get-ChildItemGet-Content 的说明,分别为:

  • 现在PowerShell是跨平台的,这些别名仅存在于PowerShell的 Windows 版本中,而是决定在Unix平台上从PowerShell Core中省略它们,以免影响同名的标准Unix实用程序。

  • 养成使用PowerShell的自己的别名的习惯更好,这些习惯遵循规定的命名惯例,并且不与平台冲突 - 具体的公用事业。

    • 例如,gci可用于Get-ChildItemgc用于Get-Content
    • 有关PowerShell自己的别名背后的命名约定,请参阅documentation