如何将 powershell 哈希表转换为对象?

Den*_*nis 4 powershell hashtable pscustomobject

PowerShell 中的某些哈希表(例如使用 导入的Import-PowerShellDataFile哈希表)如果改为 PSCustomObject,则导航起来会容易得多。

@{
    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'
    }
}
Run Code Online (Sandbox Code Playgroud)

导入后它将成为哈希表的哈希表

$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
Run Code Online (Sandbox Code Playgroud)

当按属性名称导航时,数据结构会很奇怪。

mkl*_*nt0 12

现有答案中有很好的信息,但考虑到您问题的通用标题,让我尝试系统概述

  • 您不需要哈希表转换为[pscustomobject]实例,以便使用点表示法深入了解其条目(属性),如评论中所讨论的以及iRon 的答案中所演示的。

  • 事实上,在可能的情况下,使用哈希表比使用 s更可取[pscustomobject],因为:

    • 它们比实例更轻[pscustomobject](使用更少的内存)
    • 迭代地构建它们并根据需要添加/删除条目更容易。

笔记:


如果您确实需要将 a 转换[hasthable]为 a[pscustomobject]

虽然许多标准 cmdlet 接受[hasthable]s与s互换[pscustomobjects],但有些 cmdlet接受 s ,特别是ConvertTo-Csvand (有关更改这一点的功能请求,Export-Csv请参阅GitHub 问题 #10999 );在这种情况下,[pscustomobject]必须转换为。

警告:Hastables 可以有任何类型的键,而转换[pscustomobject]总是需要使用字符串“keys”,即属性名称。因此,并非所有哈希表都可以忠实地或有意义地转换为[pscustomobject]s。

  • 将非嵌套哈希表转换为[pscustomobject]

    • PowerShell 为[pscustomobject]文字提供的语法糖(例如[pscustomobject] @{ foo = 'bar'; baz = 42 })也可以通过预先存在的哈希来工作;例如:

      $hash = @{ foo = 'bar'; baz = 42 } 
      $custObj = [pscustomobject] $hash   # Simply cast to [pscustomobject]
      
      Run Code Online (Sandbox Code Playgroud)
  • 将嵌套哈希表(即对象图)转换为[pscustomobject]图:

    • 您自己的答案中显示了一种简单但有限且可能昂贵的解决方案:使用 将哈希表转换为 JSON ConvertTo-Json,然后使用 将生成的 JSON 重新转换为[pscustomobject]图表ConvertFrom-Json

      • 抛开性能不谈,这种方法的根本限制是类型保真度可能会丢失,因为 JSON 仅支持少数数据类型。虽然不关心通过 读取的哈希表Import-PowerShellDataFile,但给定的哈希表可能包含在 JSON 中没有有意义表示的类型实例。
    • 您可以使用自定义转换函数ConvertFrom-HashTable来克服此限制(源代码如下);例如(用 检查结果Format-Custom -InputObject $custObj):

      $hash = @{ foo = 'bar'; baz = @{ quux = 42 } } # nested hashtable
      $custObj = $hash | ConvertFrom-HashTable # convert to [pscustomobject] graph
      
      Run Code Online (Sandbox Code Playgroud)

ConvertFrom-HashTable源代码:

注意:尽管有这个名称,该函数通常支持作为输入实现的类型实例IDictionary

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.
  }
}
Run Code Online (Sandbox Code Playgroud)