繁体   English   中英

如何将 powershell 哈希表转换为 object?

[英]How do I convert a powershell hashtable to an object?

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

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

$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

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

问题是什么?

@'
@{
    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'
    }
}
'@ |Set-Content .\nodes.psd1
$psdnode = Import-PowerShellDataFile .\nodefile.psd1

$psdnode

Name                           Value
----                           -----
NonNodeData                    {Comment}
AllNodes                       {SRV1, SRV2, SRV3, SRV4…}
$psdnode.AllNodes.where{ $_.NodeName -eq 'SRV3' }.Role
WebFrontEnd

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

  • 不需要哈希表转换为[pscustomobject]实例,以便使用点符号深入了解其条目(属性) ,如评论中所讨论和iRon 的回答中所展示的那样。

    • 一个简单的例子:

       @{ top = @{ nested = 'foo' } }.top.nested # -> 'foo'
    • 有关详细信息,请参阅此答案

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

    • 它们比[pscustomobject]实例更轻(使用更少的内存)
    • 迭代构建和修改它们更容易。

笔记:


确实需要将[hasthable]转换为 [pscustomobject [pscustomobject]的情况下

虽然许多标准 cmdlet 接受[hasthable][pscustomobjects]互换,但有些不接受,特别是ConvertTo-CsvExport-Csv (请参阅GitHub 问题 #10999以获取更改它的功能请求); 在这种情况下,必须转换为[pscustomobject]

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

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

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

       $hash = @{ foo = 'bar'; baz = 42 } $custObj = [pscustomobject] $hash # Simply cast to [pscustomobject]
  • 嵌套哈希表(即 object)转换为[pscustomobject]图:

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

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

       $hash = @{ foo = 'bar'; baz = @{ quux = 42 } } # nested hashtable $custObj = $hash | ConvertFrom-HashTable # convert to [pscustomobject] graph

ConvertFrom-HashTable源码:

注意:尽管名称如此,function 通常支持实现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[$entry.Key] = ConvertFrom-HashTable -HashTable $entry.Value
      } else { # Copy value as-is.
        $oht[$entry.Key] = $entry.Value
      }
    }
    [pscustomobject] $oht # Convert to [pscustomobject] and output.
  }
}

我昨天才发现的一种非常简单的方法是对 JSON 进行“双重转换”。

$nodes = Import-PowerShellDataFile .\nodes.psd1 | ConvertTo-Json | ConvertFrom-Json

$nodes

AllNodes
--------
{@{NodeName=SRV1; RunCentralAdmin=True; Role=Application}, @{NodeName=SRV2; RunCentralAdm...}

$nodes.GetType()   

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM