powershellhashtablepscustomobject

How do I convert a powershell hashtable to an object?


Some hashtables in PowerShell, such as those imported with Import-PowerShellDataFile, would be much easier to navigate if being a PSCustomObject instead.

@{
    AllNodes = @(
        @{
            NodeName = 'SRV1'
            Role = 'Application'
            RunCentralAdmin = $true
        },
        @{
            NodeName = 'SRV2'
            Role = 'DistributedCache'
            RunCentralAdmin = $true
        },
        @{
            NodeName = 'SRV3'
            Role = 'WebFrontEnd'
            PSDscAllowDomainUser = $true
            PSDscAllowPlainTextPassword = $true
            CertificateFolder = '\\mediasrv\Media'
        },
        @{
            NodeName = 'SRV4'
            Role = 'Search'
        },
        @{
            NodeName = '*'
            DatabaseServer = 'sql1'
            FarmConfigDatabaseName = '__FarmConfig'
            FarmContentDatabaseName = '__FarmContent'
            CentralAdministrationPort = 1234
            RunCentralAdmin = $false
        }
    );
    NonNodeData = @{
        Comment = 'No comment'
    }
}

When imported it will become a hashtable of hashtables

$psdnode = Import-PowerShellDataFile .\nodefile.psd1

$psdnode

Name                           Value
----                           -----
AllNodes                       {System.Collections.Hashtable, System.Collect...
NonNodeData                    {Comment}

$psdnode.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object

and the data structure will be just weird when navigating by property name.


Solution

  • There's good information in the existing answers, but given your question's generic title, let me try a systematic overview:

    Note:


    In cases where you do need to convert a [hasthable] to a [pscustomobject]:

    While many standard cmdlets accept [hasthable]s interchangeably with [pscustomobjects]s, some do not, notably ConvertTo-Csv and Export-Csv (see GitHub issue #10999 for a feature request to change that); in such cases, conversion to [pscustomobject] is a must.

    Caveat: Hasthables can have keys of any type, whereas conversion to [pscustomobject] invariably requires using string "keys", i.e. property names. Thus, not all hashtables can be faithfully or meaningfully converted to [pscustomobject]s.


    ConvertFrom-HashTable source code:

    Note: Despite the name, the function generally supports instance of types that implement IDictionary as input.

    function ConvertFrom-HashTable {
      param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.Collections.IDictionary] $HashTable
      )
      process {
        $oht = [ordered] @{} # Aux. ordered hashtable for collecting property values.
        foreach ($entry in $HashTable.GetEnumerator()) {
          if ($entry.Value -is [System.Collections.IDictionary]) { # Nested dictionary? Recurse.
            $oht[[object] $entry.Key] = ConvertFrom-HashTable -HashTable $entry.Value # NOTE: Casting to [object] prevents problems with *numeric* hashtable keys.
          } else { # Copy value as-is.
            $oht[[object] $entry.Key] = $entry.Value
          }
        }
        [pscustomobject] $oht # Convert to [pscustomobject] and output.
      }
    }