Подтвердить что ты не робот

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?

4b9b3361

Ответ 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 уровня, но рекурсивный, пока у него не будет полной хэш-таблицы.