Hashtables из ConvertFrom-json имеют другой тип из встроенных хэш-таблиц powershells, как я могу сделать их одинаковыми?
У меня есть json файл (test.json), который выглядит примерно так:
{
"root":
{
"key":"value"
}
}
Я загружаю его в powershell, используя что-то вроде этого:
PS > $data = [System.String]::Join("", [System.IO.File]::ReadAllLines("test.json")) | ConvertFrom-Json
root
----
@{key=value}
Я хотел бы иметь возможность перечислять ключи объекта hashtable, как это определено json файлом. Итак, в идеале, я хотел бы что-то сделать как:
$data.root.Keys
и получите [ "ключ" ] назад. Я могу сделать это со встроенными хэш-таблицами в powershell, но делать это с хэш-таблицей, загруженной из json, менее очевидно.
При устранении этой проблемы я заметил, что поля, возвращаемые ConvertFrom-json, имеют разные типы, отличные от полей hashtables Powershell. Например, вызов .GetType() во встроенной хэш-таблице показывает, что он имеет тип "Hashtable":
PS > $h = @{"a"=1;"b"=2;"c"=3}
PS > $h.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Hashtable System.Object
делая то же самое для моего json-объекта, дает PSCustomObject:
PS > $data.root.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
Есть ли способ сбрасывать или преобразовывать этот объект в обычную файловую панель Hashtable?
Ответы
Ответ 1
Командлет ConvertFrom-Json
предоставляет пользовательский объект, поэтому вам нужно получить к ним доступ с использованием точечной нотации, а не как индекс. Обычно вы знаете, какие поля вы ожидаете в JSON, поэтому на самом деле это более полезно в целом, чем получение хеш-таблицы. Вместо того, чтобы бороться с системой, обратившись к хеш-таблице, я предлагаю вам работать с ней.
Вы можете использовать select
с именами свойств подстановочных знаков, чтобы получить свойства:
PS D:\> $data = @"
{
"root":
{
"key":"value", "key2":"value2", "another":42
}
}
"@ | ConvertFrom-Json
PS D:\> $data.root | select * | ft -AutoSize
key key2 another
--- ---- -------
value value2 42
PS D:\> $data.root | select k* | ft -AutoSize
key key2
--- ----
value value2
и Get-Member
, если вы хотите извлечь список имен свойств, которые вы можете перебрать:
PS D:\> ($data.root | Get-Member -MemberType NoteProperty).Name
another
key
key2
Ввод этого в цикл дает такой код:
PS D:\> foreach ($k in ($data.root | Get-Member k* -MemberType NoteProperty).Name) {
Write-Output "$k = $($data.root.$k)"
}
key = value
key2 = value2
Ответ 2
Вот быстрая функция преобразования PSObject обратно в хэш-таблицу (с поддержкой вложенных объектов, предназначенная для использования с DSC ConfigurationData, но может использоваться там, где вам это нужно).
function ConvertPSObjectToHashtable
{
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
{
$collection = @(
foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object }
)
Write-Output -NoEnumerate $collection
}
elseif ($InputObject -is [psobject])
{
$hash = @{}
foreach ($property in $InputObject.PSObject.Properties)
{
$hash[$property.Name] = ConvertPSObjectToHashtable $property.Value
}
$hash
}
else
{
$InputObject
}
}
}
Ответ 3
Пример был для относительно мелкого исходного объекта (не вложенных объектов в свойствах).
Здесь версия, которая пройдет 2 уровня в глубину исходного объекта и должна работать с вашими данными:
$data = @{}
foreach ($propL1 in $x.psobject.properties.name)
{
$data[$propL1] = @{}
foreach ($propL2 in $x.$propL1.psobject.properties.name)
{
$data[$PropL1][$PropL2] = $x.$propL1.$propL2
}
}
$data.root.keys
key
Ответ 4
@Duncan: Если вам нужно использовать JSON Input для команды, ожидающей хэш-карту (например, SET-ADUSER), попробуйте что-то вроде этого:
function SetADProperties{
param($PlannedChanges)
$UserName = $PlannedChanges.Request.User
$Properties = @{}
foreach ($key in ($PlannedChanges.SetADProperties | Get-Member -MemberType NoteProperty).Name)
{
$Properties[$key] = $PlannedChanges.SetADProperties.$key
}
# Call Set-ADUser only once, not in a loop
Set-ADUser -Identity $UserName -Replace $Properties
}
$content = Get-Content -encoding UTF8 $FileName
$PlannedChanges = $content | ConvertFrom-Json
SetADProperties $PlannedChanges | Write-Output
Пример JSON:
{"SetADProperties":{"postalCode":"01234","l":"Duckburg","employeenumber":"012345678"},
"Request":{"Action":"UserMove","User":"WICHKIND","Change":"CH1506-00023"}}
Ответ 5
Я поставил это вместе для обработки вложенных json в hashtables
function ConvertJSONToHash{
param(
$root
)
$hash = @{}
$keys = $root | gm -MemberType NoteProperty | select -exp Name
$keys | %{
$key=$_
$obj=$root.$($_)
if($obj -match "@{")
{
$nesthash=ConvertJSONToHash $obj
$hash.add($key,$nesthash)
}
else
{
$hash.add($key,$obj)
}
}
return $hash
}
Я тестировал только 4 уровня, но рекурсивный, пока у него не будет полной хэш-таблицы.