Powershell-使用ConvertTo Json保留所有枚举属性的文本

Powershell-使用ConvertTo Json保留所有枚举属性的文本,json,powershell,enums,Json,Powershell,Enums,对于“Get-MsoldDomain”powershell命令,让我获得下面的输出(称之为输出#1),其中名称、状态和身份验证是属性名称,下面是它们各自的值 Name Status Authentication myemail.onmicrosoft.com Verified Managed 当我将命令与下面的“converttojson”一起使用时 GetMsolDomain |ConvertTo-Json 我得到了以下Json格式的输出(我们称

对于“Get-MsoldDomain”powershell命令,让我获得下面的输出(称之为输出#1),其中名称、状态和身份验证是属性名称,下面是它们各自的值

Name                    Status   Authentication

myemail.onmicrosoft.com Verified Managed
当我将命令与下面的“converttojson”一起使用时

GetMsolDomain |ConvertTo-Json
我得到了以下Json格式的输出(我们称之为output#2)

{
    "ExtensionData":  {

                      },
    "Authentication":  0,
    "Capabilities":  5,
    "IsDefault":  true,
    "IsInitial":  true,
    "Name":  "myemail.onmicrosoft.com",
    "RootDomain":  null,
    "Status":  1,
    "VerificationMethod":  1
}
但是,问题是,如果您注意到两个输出中的Status属性,则它是不同的。验证方法属性也会发生同样的情况。不使用ConvertTo JSon,Powershell将给出文本,使用ConvertTo JSon将给出整数

当我发出以下命令时

get-msoldomain |Select-object @{Name='Status';Expression={"$($_.Status)"}}|ConvertTo-json
我得到的输出是

{
    "Status":  "Verified"
}
但是,我需要一些东西,这样我就不必为转换它指定任何特定的属性名,就像我在上面指定的那样

Select-object @{Name='Status';Expression={"$($_.Status)"}}
此行仅转换状态属性,而不是验证方法属性,因为这是我作为输入提供的内容

问:我是否可以给“ConvertTo Json”命令提供一些通用的东西,以便它以文本而不是整数的形式返回枚举属性,而不显式地命名它们,这样我就可以得到如下输出:

{
    "ExtensionData":  {

                      },
    "Authentication":  0,
    "Capabilities":  5,
    "IsDefault":  true,
    "IsInitial":  true,
    "Name":  "myemail.onmicrosoft.com",
    "RootDomain":  null,
    "Status":  "Verified",
    "VerificationMethod":  "DnsRecord"
}

好的,如果您不介意进行一次小旅行:)您可以将其转换为CSV,这将强制字符串输出,然后将其从CSV重新转换回PS对象,最后再转换回Json

像这样:

Get-MsolDomain | ConvertTo-Csv | ConvertFrom-Csv | ConvertTo-Json
  • 如果您需要保留原始类型,而不是将其全部转换为字符串,请参阅mklement0帮助答案
PowerShell Core(PowerShell第6版及以上版本)通过的
-EnumsAsStrings
开关提供了一个简单的解决方案

GetMsolDomain | ConvertTo-Json -EnumsAsStrings  # PS *Core* (v6+) only

不幸的是,Windows PowerShell不支持此开关

GetMsolDomain | ConvertTo-Json -EnumsAsStrings  # PS *Core* (v6+) only
但是,提供了一个快速的解决方案,该解决方案附带了一个大的警告:所有属性值在该过程中都会转换为字符串,这通常是不可取的(例如,
身份验证
属性的
0
数值将转换为字符串
'0'

这里有一个更通用的解决方案,它基于一个过滤器函数,递归地内省输入对象并输出有序哈希表,这些哈希表反映了输入属性,枚举值转换为字符串和所有其他传递的值,然后您可以将这些值传递到
converttojson

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
    }
  }
}
警告:与
转换为Json
一样,递归深度(
-depth
)在默认情况下被限制为
2
,以防止无限递归/过大的输出(例如,通过
获取ChildItem
,可以获得
[System.IO.FileInfo]
等类型)。类似地,超过隐含深度或指定深度的值由其
.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
是默认值(并且输入的Depth
0
),但在这里显示它是为了提醒您可能需要显式控制它。

一个简单实用的解决方案,但是(效率除外)它附带了一个很大的警告:所有属性值都会转换为字符串,这通常是不可取的。这是一个比公认的答案好得多的答案