Powershell создает объект из нескольких файлов

Я создаю объект PSObject из файла json

bar.json

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

Я могу создать PSCustomObject из json, используя ConvertFrom-Json

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

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

Однако, если я попытаюсь разложить несколько файлов 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

Обновление
По запросу Уолтера Митти. Если я загружаю один файл и запускаю $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}
}

person spuder    schedule 09.12.2016    source источник
comment
Что вы ожидаете, если два файла / объекта json будут иметь одно и то же свойство с разными значениями?   -  person Andrew    schedule 09.12.2016
comment
Хороший момент, я бы ожидал ошибки, если какой-либо ключ не уникален.   -  person spuder    schedule 09.12.2016
comment
Могу ошибаться, но я считаю, что массив объектов - это объект.   -  person Walter Mitty    schedule 09.12.2016
comment
Попробуйте $ foo [0] .gettype или $ foo [0] | gm, чтобы узнать больше о первой записи в $ foo.   -  person Walter Mitty    schedule 09.12.2016


Ответы (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

Это создаст карту Name -> Data для всех ваших файлов JSON в виде вложенного PSObject

person AP.    schedule 09.12.2016
comment
В мире Linux не рекомендуется анализировать вывод ls. Окна такие же? - person spuder; 09.12.2016
comment
Ничто в PowerShell на самом деле не возвращает просто строки, это объекты с полями ... - person AP.; 09.12.2016
comment
@spuder ls и cat в powershell - это внутренние псевдонимы для get-childitem и get-content @AP. Я получаю эту ошибку с вашим кодом The splatting operator '@' cannot be used to reference variables in an expression. - person ; 09.12.2016

Полезный ответ AP - это элегантное решение для создания одного объекта верхнего уровня ([pscustomobject] экземпляр), который:

  • содержит все объекты, преобразованные в JSON, как свойства, названные по именам их входных файлов.

    • Например, $final будет содержать свойство bar.json, значение которого является объектным эквивалентом строки JSON из вопроса.

    • Предостережение: с повторяющимися именами файлов «выиграет» последний обработанный файл.

См. примечание по использованию псевдонимов в стиле Unix ls и cat.


Чтобы получить массив всех преобразованных из JSON объектов, достаточно следующего:

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

Обратите внимание: если вам нужны JSON-файлы одного каталога,
$allObjects = @(Get-Content -Path *.json -Raw | ConvertFrom-Json) тоже подойдет.

Обратите внимание на использование @(...), оператора подвыражения array, который гарантирует, что то, что возвращается, обрабатывается как массив, даже если только одиночный объект возвращается.

  • По умолчанию или когда вы используете $(...), обычный оператор подвыражения, PowerShell разворачивает любую (потенциально вложенную) коллекцию отдельных элементов и возвращает только сам элемент; см. Get-Help about_Operators.

Примечание об использовании псевдонимов в стиле Unix ls и cat для командлетов Get-ChildItem и Get-Content PowerShell соответственно:

  • Теперь, когда PowerShell является кроссплатформенным, эти псевдонимы существуют только в версии PowerShell для Windows, тогда как было принято решение исключить их из PowerShell Core на платформах Unix, чтобы не дублировать стандартные утилиты Unix. с таким же названием.

  • Лучше выработать привычку использовать собственные псевдонимы PowerShell, которые следуют предписанным соглашениям об именах и не конфликтуют с утилитами для конкретной платформы.

    • E.g., gci can be used for Get-ChildItem, and gc for Get-Content
    • Соглашения об именах собственных псевдонимов PowerShell см. В документация.
person mklement0    schedule 09.12.2016