对于" Get-Msoldomain " powershell命令 - 让我得到以下输出(让我们称之为输出#1 ),其中Name,Status和Authentication是属性名称,下面是它们各自的值。
Name Status Authentication
myemail.onmicrosoft.com Verified Managed
当我使用" ConvertTo-Json"如下所示
GetMsolDomain |ConvertTo-Json
我以Json格式得到以下输出(让我们称之为输出#2 )。
{
"ExtensionData": {
},
"Authentication": 0,
"Capabilities": 5,
"IsDefault": true,
"IsInitial": true,
"Name": "myemail.onmicrosoft.com",
"RootDomain": null,
"Status": 1,
"VerificationMethod": 1
}
然而,问题是,如果您在两个输出中都注意到状态属性,则它会有所不同。 VerificationMethod 属性也是如此。不使用ConvertTo-JSon Powershell给出Text,并使用ConvertTo-Json给出整数。
当我发出以下命令时
get-msoldomain |Select-object @{Name='Status';Expression={"$($_.Status)"}}|ConvertTo-json
我得到输出为
{
"Status": "Verified"
}
但是,我想要一些东西,以便我不必为其转换指定任何特定的属性名称,我在上面指定的方式为
Select-object @{Name='Status';Expression={"$($_.Status)"}}
此行仅转换状态属性,而不是 VerificationMethod 属性,因为这是我提供的输入。
问题:是否有一些通用的东西我可以给" ConvertTo-Json "命令行,以便它将 ALL 枚举属性作为文本而非整数返回,而不显式命名它们,以便我得到类似下面的内容作为输出:
{
"ExtensionData": {
},
"Authentication": 0,
"Capabilities": 5,
"IsDefault": true,
"IsInitial": true,
"Name": "myemail.onmicrosoft.com",
"RootDomain": null,
"Status": "Verified",
"VerificationMethod": "DnsRecord"
}
答案 0 :(得分:6)
好吧,如果你不介意去旅行:)你可以将它转换为CSV,这将强制输出字符串,然后将其从CSV重新转换回PS对象,最后返回Json
像这样:
Get-MsolDomain | ConvertTo-Csv | ConvertFrom-Csv | ConvertTo-Json
答案 1 :(得分:2)
PowerShell Core 通过ConvertTo-Json
的 -EnumsAsStrings
开关提供了一种简单的解决方案。
GetMsolDomain | ConvertTo-Json -EnumsAsStrings # PS *Core* only
不幸的是, Windows PowerShell 不支持该开关。
Avshalom's answer提供了一个快速的解决方法,但需要注意以下事项:所有属性值在此过程中总是转换为字符串,这通常是不希望的。
这是基于过滤器功能的更通用的解决方法,它递归内省输入对象并输出有序哈希表,这些哈希表反映了输入属性,枚举值转换为字符串,并通过所有其他值,然后可以传递给ConvertTo-Json
:
Filter ConvertTo-EnumsAsStrings ([int] $Depth = 2, [int] $CurrDepth = 0) {
if ($_ -is [enum]) { # enum value -> convert to symbolic name as string
$_.ToString()
} elseif ($null -eq $_ -or $_.GetType().IsPrimitive -or $_ -is [string] -or $_ -is [decimal] -or $_ -is [datetime] -or $_ -is [datetimeoffset]) {
$_
} elseif ($_ -is [Collections.IEnumerable]) {
, ($_ | ConvertTo-EnumsAsStrings -Depth $Depth -CurrDepth ($CurrDepth+1))
} else { # non-primitive type -> recurse on properties
if ($CurrDepth -gt $Depth) { # depth exceeded -> return .ToString() representation
"$_"
} else {
$oht = [ordered] @{}
foreach ($prop in $_.psobject.properties) {
if ($prop.Value -is [Collections.IEnumerable] -and -not $prop.Value -is [string]) {
$oht[$prop.Name] = @($prop.Value | ConvertTo-EnumsAsStrings -Depth $Depth -CurrDepth ($CurrDepth+1))
} else {
$oht[$prop.Name] = $prop.Value | ConvertTo-EnumsAsStrings -Depth $Depth -CurrDepth ($CurrDepth+1)
}
}
$oht
}
}
}
注意事项:与ConvertTo-Json
一样,默认情况下递归深度(-Depth
)限制为2
,以防止无限递归/输出过大(例如您通过[System.IO.FileInfo]
使用Get-ChildItem
这样的类型)。同样,超出隐含或指定深度的值由其.ToString()
值表示。明确使用-Depth
来控制递归深度。
示例调用:
PS> [pscustomobject] @{ p1 = [platformId]::Unix; p2 = 'hi'; p3 = 1; p4 = $true } |
ConvertTo-EnumsAsStrings -Depth 2 |
ConvertTo-Json
{
"p1": "Unix", # Enum value [platformId]::Unix represented as string.
"p2": "hi", # Other types of values were left as-is.
"p3": 1,
"p4": true
}
注意:假设-Depth 2
是默认值(并且输入的深度为2
),此处0
并不是必需的,但此处显示提醒您可能要显式控制它。
答案 2 :(得分:1)
我需要将 pwsh 对象序列化为 JSON,但无法使用 -EnumsAsStrings
的 ConvertTo-Json
参数,因为我的代码在 psv5 上运行。由于我在使用@mklement0 的代码时遇到了无限循环编者注:因为已修复。,我重新编写了它。我修改后的代码还处理了一些其他类型(例如日期)的序列化,将它们序列化为 ISO 8601 格式,这通常是在 JSON 中表示日期的公认方式。随意使用它,如果您遇到任何问题,请告诉我。
Filter ConvertTo-EnumsAsStrings ([int] $Depth = 10, [int] $CurrDepth = 0) {
if ($CurrDepth -gt $Depth) {
Write-Error "Recursion exceeded depth limit of $Depth"
return $null
}
Switch ($_) {
{ $_ -is [enum] -or $_ -is [version] -or $_ -is [IPAddress] -or $_ -is [Guid] } {
$_.ToString()
}
{ $_ -is [datetimeoffset] } {
$_.UtcDateTime.ToString('o')
}
{ $_ -is [datetime] } {
$_.ToUniversalTime().ToString('o')
}
{ $_ -is [timespan] } {
$_.TotalSeconds
}
{ $null -eq $_ -or $_.GetType().IsPrimitive -or $_ -is [string] -or $_ -is [decimal] } {
$_
}
{ $_ -is [hashtable] } {
$ht = [ordered]@{}
$_.GetEnumerator() | ForEach-Object {
$ht[$_.Key] = ($_.Value | ConvertTo-EnumsAsStrings -Depth $Depth -CurrDepth ($CurrDepth + 1))
}
if ($ht.Keys.Count) {
$ht
}
}
{ $_ -is [pscustomobject] } {
$ht = [ordered]@{}
$_.PSObject.Properties | ForEach-Object {
if ($_.MemberType -eq 'NoteProperty') {
Switch ($_) {
{ $_.Value -is [array] -and $_.Value.Count -eq 0 } {
$ht[$_.Name] = @()
}
{ $_.Value -is [hashtable] -and $_.Value.Keys.Count -eq 0 } {
$ht[$_.Name] = @{}
}
Default {
$ht[$_.Name] = ($_.Value | ConvertTo-EnumsAsStrings -Depth $Depth -CurrDepth ($CurrDepth + 1))
}
}
}
}
if ($ht.Keys.Count) {
$ht
}
}
Default {
Write-Error "Type not supported: $($_.GetType().ToString())"
}
}
}