PSCustomObject для Hashtable


77

Який найпростіший спосіб перетворити a PSCustomObjectна a Hashtable? Він відображається так само, як один із оператором splat, фігурними дужками і, здається, парами ключових значень. Коли я намагаюся кинути це, [Hashtable]це не працює. Я також спробував, .toString()і призначена змінна каже, що це рядок, але нічого не відображає - будь-які ідеї?


1
PSCustomObjects мають переваги перед хештегом. Подумайте двічі, перш ніж перетворити його. stackoverflow.com/questions/22002748 / ...
spuder

1
Бризок не працює з PSCustomObject, це вагома причина, про яку я можу придумати.
Brain2000

Відповіді:


98

Це не повинно бути занадто важко. Щось на зразок цього повинно зробити трюк:

# Create a PSCustomObject (ironically using a hashtable)
$ht1 = @{ A = 'a'; B = 'b'; DateTime = Get-Date }
$theObject = new-object psobject -Property $ht1

# Convert the PSCustomObject back to a hashtable
$ht2 = @{}
$theObject.psobject.properties | Foreach { $ht2[$_.Name] = $_.Value }

Зверніть увагу, що $_.Nameце вже рядок, тому $ht2[$_.Name]або $h.($_.Name)буде працювати так само добре, як "$($_.Name)".
Імператор XLII

12
Зверніть увагу, що це не працює для PSCustomObjects, створених ConvertFrom-Json. Це питання стосується цього питання.
BenV

4
@BenV: Тільки для уточнення: проблема виникає із вкладених користувацьких об’єктів, а не з використання ConvertFrom-Jsonяк такої, що також створює [PSCustomObject]екземпляри. Іншими словами: джерело JSON, яке виробляє вкладені об'єкти, працює чудово; наприклад:('{ "foo": "bar" }' | ConvertFrom-Json).psobject.properties | % { $ht = @{} } { $ht[$_.Name] = $_.Value } { $ht }
mklement0

2
Кастинг може стати реальністю в майбутньому: connect.microsoft.com/PowerShell/feedback/details/679841/…
W1M0R

Дивіться нижче відповідь @ Святослава Підгорного, який використовує нові функції PowerShell 6 або 7 для більш простого підходу! stackoverflow.com/a/61742479/3425553
Ігор

28

Кіт вже дав вам відповідь, це лише ще один спосіб зробити те саме з одноклассником:

$psobject.psobject.properties | foreach -begin {$h=@{}} -process {$h."$($_.Name)" = $_.Value} -end {$h}

Хе, почав із чогось дуже подібного, за винятком того, що для виклику SO горизонтальної смуги прокрутки було достатньо довго. До речі, я думаю, що у вас $'sбракує деяких _'s. :-)
Кіт Хілл

Ось чого я намагався уникнути, і врешті-решт він проковтнув знак підкреслення. Дякую!
Шей Леві,

@ShayLevy: Яка перевага ставити все на одну лінію?
Рубанов

2
Приємно; якщо ви використовуєте % і позиційні параметри як блоки, ви можете скоротити до $psobject.psobject.properties | % { $ht = @{} } { $ht[$_.Name] = $_.Value } { $ht }. @Rubanov: Це не повинно бути в одному рядку , але перевага полягає в тому, що одне твердження (конвеєр) створює хеш-таблицю.
mklement0

24

Ось версія, яка також працює з вкладеними хеш-тегами / масивами (що корисно, якщо ви намагаєтесь зробити це за допомогою 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
Це єдина версія, яка працювала для моїх даних із багаторівневими вкладеними об’єктами та масивами.
Джеффрі Хармон,

3
Відмінне та елегантне рішення для багаторівневих вкладених об’єктів.
Петру Захарія,

Як зазначалося в коментарі до попередньої відповіді, цей код обробляє складні / вкладені хештеги і чудово підходить для обробки вмісту з ConvertFrom-Json. Дивіться також це запитання
Томас

Я не можу змусити це працювати "як є" для вкладених об'єктів: @{ Name = "test1"; nested = @{ license = 'x'; cert = 'y' } } | Convert-PSObjectToHashTable Натомість мені довелося додати GetEnumerator()рядок 15:foreach ($object in $InputObject.GetEnumerator()) { ConvertPSObjectToHashtable $object }
Кіт Гарнер

Той самий код Адама Бертрама можна знайти тут: 4sysops.com/archives/convert-json-to-a-powershell-hash-table
Ciove

4

Мій надзвичайно ледачий підхід, увімкнений завдяки новій функції PowerShell 6:

$myhashtable = $mypscustomobject | ConvertTo-Json | ConvertFrom-Json -AsHashTable

Мені подобається цей!
Ігор

Я сподівався уникнути використання цього, тому що здаватись абсурдним робити зворотну подорож до тексту та назад до формату об’єкта ... але я можу підтвердити, що це не працює, і це найзручніше (якщо не виконано) синтаксис.
jrypkahauer

3

Це працює для PSCustomObjects, створених ConvertFrom_Json.

Function ConvertConvertFrom-JsonPSCustomObjectToHash($obj)
{
    $hash = @{}
     $obj | Get-Member -MemberType Properties | SELECT -exp "Name" | % {
                $hash[$_] = ($obj | SELECT -exp $_)
      }
      $hash
}

Застереження: Я ледве розумію PowerShell, тому це, мабуть, не так чисто, як могло б бути. Але це працює (лише для одного рівня).


1
Трохи чистіший (можливо, це важче зрозуміти)$hash=@{};$obj | Get-Member -MemberType Properties | foreach { $hash.Add($_.Name,$obj.($_.Name))}
Адарша,

2

Мій код:

function PSCustomObjectConvertToHashtable() {
    param(
        [Parameter(ValueFromPipeline)]
        $object
    )

    if ( $object -eq $null ) { return $null }

    if ( $object -is [psobject] ) {
        $result = @{}
        $items = $object | Get-Member -MemberType NoteProperty
        foreach( $item in $items ) {
            $key = $item.Name
            $value = PSCustomObjectConvertToHashtable -object $object.$key
            $result.Add($key, $value)
        }
        return $result
    } elseif ($object -is [array]) {
        $result = [object[]]::new($object.Count)
        for ($i = 0; $i -lt $object.Count; $i++) {
            $result[$i] = (PSCustomObjectConvertToHashtable -object $object[$i])
        }
        return ,$result
    } else {
        return $object
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.