[英]How do I correctly convert a HashTable to JSON in PowerShell?
[英]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]
实例更轻(使用更少的内存)笔记:
以上不仅适用于[hashtable]
类型,而且更普遍地适用于实现[System.Collections.IDictionary]
接口或其通用对应物System.Collections.Generic.IDictionary[TKey, TValue]]
的类型的实例,特别是包括有序哈希表(它们是System.String
类型的实例,PowerShell 允许您使用语法糖[ordered] @{... }
构造)。
除非另有说明,否则下一节中的哈希表指的是所有这些类型。
在确实需要将[hasthable]
转换为 [pscustomobject [pscustomobject]
的情况下:
虽然许多标准 cmdlet 接受[hasthable]
与[pscustomobjects]
互换,但有些不接受,特别是ConvertTo-Csv
和Export-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]
图。
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.