PSCustomObject to Hashtable

76

Was ist der einfachste Weg, um a PSCustomObjectin a umzuwandeln Hashtable? Es wird genau wie eins mit dem Splat-Operator, geschweiften Klammern und scheinbar Schlüsselwertpaaren angezeigt. Wenn ich versuche, es zu [Hashtable]besetzen, funktioniert es nicht. Ich habe es auch versucht .toString()und die zugewiesene Variable sagt, es sei eine Zeichenfolge, zeigt aber nichts an - irgendwelche Ideen?

alphadev
quelle
1
PSCustomObjects haben Vorteile gegenüber Hashtabellen. Überlegen Sie zweimal, bevor Sie es konvertieren. stackoverflow.com/questions/22002748/…
spuder
1
Splatting funktioniert nicht mit einem PSCustomObject, ist ein guter Grund, den ich mir vorstellen kann.
Brain2000

Antworten:

94

Sollte nicht zu schwer sein. So etwas sollte den Trick machen:

# 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 }
Keith Hill
quelle
Beachten Sie, dass dies $_.Namebereits eine Zeichenfolge ist, $ht2[$_.Name]oder $h.($_.Name)genauso gut funktioniert wie "$($_.Name)".
Kaiser XLII
10
Beachten Sie, dass dies für PSCustomObjects, die von erstellt wurden, nicht funktioniert ConvertFrom-Json. Diese Frage behebt dieses Problem.
BenV
4
@BenV: Nur zur Verdeutlichung: Das Problem ergibt sich aus verschachtelten benutzerdefinierten Objekten, nicht aus der Verwendung von ConvertFrom-Jsonper se, die auch [PSCustomObject]Instanzen erzeugt . Mit anderen Worten: Eine JSON-Quelle, die nicht verschachtelte Objekte erzeugt, funktioniert einwandfrei. zB:('{ "foo": "bar" }' | ConvertFrom-Json).psobject.properties | % { $ht = @{} } { $ht[$_.Name] = $_.Value } { $ht }
mklement0
2
Casting könnte in Zukunft Realität werden: connect.microsoft.com/PowerShell/feedback/details/679841/…
W1M0R
Unten finden Sie eine Antwort von @Svyatoslav Pidgorny, der neue Funktionen in PowerShell 6 oder 7 verwendet, um einen einfacheren Ansatz zu finden! stackoverflow.com/a/61742479/3425553
Igor
28

Keith hat Ihnen bereits die Antwort gegeben, dies ist nur eine andere Möglichkeit, dasselbe mit einem Einzeiler zu tun:

$psobject.psobject.properties | foreach -begin {$h=@{}} -process {$h."$($_.Name)" = $_.Value} -end {$h}
Shay Levy
quelle
Heh, begann mit etwas sehr Ähnlichem, außer dass es gerade lang genug war, um die horizontale SO-Bildlaufleiste aufzurufen. Übrigens, ich denke, Ihnen $'sfehlen einige _'s. :-)
Keith Hill
Das habe ich versucht zu vermeiden und schließlich hat es den Unterstrich verschluckt. Vielen Dank!
Shay Levy
@ShayLevy: Was ist der Vorteil, wenn man alles auf die gleiche Linie bringt?
Rubanov
2
Nett; Wenn Sie % und Positionsparameter als Blöcke verwenden, können Sie auf kürzen $psobject.psobject.properties | % { $ht = @{} } { $ht[$_.Name] = $_.Value } { $ht }. @ Rubanov: Es muss nicht in einer einzelnen Zeile stehen , aber der Vorteil ist, dass eine einzelne Anweisung (Pipeline) die Hashtabelle erstellt.
mklement0
24

Hier ist eine Version, die auch mit verschachtelten Hashtabellen / Arrays funktioniert (was nützlich ist, wenn Sie dies mit DSC ConfigurationData versuchen):

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
        }
    }
}
Dave Wyatt
quelle
3
Dies ist die einzige Version, die für meine Daten mit mehrstufigen verschachtelten Objekten und Arrays funktioniert hat.
Jeffrey Harmon
3
Hervorragende und elegante Lösung für mehrstufige verschachtelte Objekte.
Petru Zaharia
Wie im Kommentar einer vorherigen Antwort erwähnt, behandelt dieser Code oben komplexe / verschachtelte Hashtabellen und eignet sich hervorragend für die Verarbeitung von Inhalten aus ConvertFrom-Json. Siehe auch diese Frage
Thomas
Ich kann dies nicht dazu bringen, "wie es ist" für verschachtelte Objekte zu funktionieren: @{ Name = "test1"; nested = @{ license = 'x'; cert = 'y' } } | Convert-PSObjectToHashTable Stattdessen musste ich in GetEnumerator()Zeile 15 foreach ($object in $InputObject.GetEnumerator()) { ConvertPSObjectToHashtable $object }
Keith S Garner
Den gleichen Code von Adam Bertram finden Sie hier: 4sysops.com/archives/convert-json-to-a-powershell-hash-table
Ciove
4

Mein extrem fauler Ansatz, der durch eine neue Funktion in PowerShell 6 ermöglicht wird:

$myhashtable = $mypscustomobject | ConvertTo-Json | ConvertFrom-Json -AsHashTable
Svyatoslav Pidgorny
quelle
Ich mag diesen!
Igor
Ich hatte gehofft, dies zu vermeiden, weil es irgendwie absurd erscheint, eine Rundreise zum Text und zurück zu einem Objektformat zu machen ... aber ich kann bestätigen, dass es nicht funktioniert und es am bequemsten ist (wenn nicht performant) Syntax.
Jrypkahauer
3

Dies funktioniert für PSCustomObjects, die von ConvertFrom_Json erstellt wurden.

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

Haftungsausschluss: Ich verstehe PowerShell kaum, daher ist dies wahrscheinlich nicht so sauber wie es sein könnte. Aber es funktioniert (nur für eine Ebene).

mhenry1384
quelle
1
Etwas sauberer (möglicherweise schwieriger zu verstehen)$hash=@{};$obj | Get-Member -MemberType Properties | foreach { $hash.Add($_.Name,$obj.($_.Name))}
Adarsha
2

Mein Code:

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
    }
}
Hu Xinlong
quelle