将 PSCustomObject 转换为 Hashtable

PSCustomObject转换成 Hashtable最简单的方法是什么?它的显示方式与 splat 操作符、大括号和键值对类似。当我试图把它转换成 [Hashtable]时,它不工作。我也尝试了 .toString()和分配的变量说它是一个字符串,但显示什么-任何想法?

91080 次浏览

Shouldn't be too hard. Something like this should do the trick:

# 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 already gave you the answer, this is just another way of doing the same with a one-liner:

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

This works for PSCustomObjects created by ConvertFrom_Json.

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

Disclaimer: I barely understand PowerShell so this is probably not as clean as it could be. But it works (for one level only).

Here's a version that works with nested hashtables / arrays as well (which is useful if you're trying to do this with 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
}
}
}

My 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
}
}

My extremely lazy approach, enabled by a new feature in PowerShell 6:

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

Today, the "easiest way" to convert PSCustomObject to Hashtable would be so:

$custom_obj | ConvertTo-HashtableFromPsCustomObject

OR

[hashtable]$custom_obj

Conversely, you can convert a Hashtable to PSCustomObject using:

[PSCustomObject]$hash_table

Only snag is, these nifty options may not be available in older versions of PS

For simple [PSCustomObject] to [Hashtable] conversion Keith's Answer works best.

However if you need more options you can use


function ConvertTo-Hashtable {
<#
.Synopsis
Converts an object to a hashtable
.DESCRIPTION
PowerShell v4 seems to have trouble casting some objects to Hashtable.
This function is a workaround to convert PS Objects to [Hashtable]
.LINK
https://github.com/alainQtec/.files/blob/main/src/scripts/Converters/ConvertTo-Hashtable.ps1
.NOTES
Base ref: https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/turning-objects-into-hash-tables-2
#>
PARAM(
# The object to convert to a hashtable
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
$InputObject,


# Forces the values to be strings and converts them by running them through Out-String
[switch]$AsString,


# If set, empty properties are Included
[switch]$AllowNulls,


# Make each hashtable to have it's own set of properties, otherwise,
# (default) each InputObject is normalized to the properties on the first object in the pipeline
[switch]$DontNormalize
)
BEGIN {
$headers = @()
}
PROCESS {
if (!$headers -or $DontNormalize) {
$headers = $InputObject | Get-Member -type Properties | Select-Object -expand name
}
$OutputHash = @{}
if ($AsString) {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col | Out-String -Width 9999 | ForEach-Object { $_.Trim() }
}
}
} else {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col
}
}
}
}
END {
return $OutputHash
}
}


Maybe this is overkill but I hope it Helps