【问题标题】:Powershell - Retain Complex objects with ConvertTo-JsonPowershell - 使用 ConvertTo-Json 保留复杂对象
【发布时间】:2017-06-13 08:37:37
【问题描述】:

Powershell command-let ConvertTo-Json 有以下限制 1)它将枚举值返回为整数而不是它们的文本 2)它不会以可读格式返回日期

对于第 1 点,请参见下文,Status 和 VerificationMethod 属性

PS C:\Windows\system32> Get-Msoldomain | ConvertTo-Json


{
    "ExtensionData":  {

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

为了解决这个问题,我改变了我的命令如下

PS C:\Windows\system32> Get-Msoldomain | ConvertTo-Csv | ConvertFrom-Csv | ConvertTo-Json

{
    "ExtensionData":  "System.Runtime.Serialization.ExtensionDataObject",
    "Authentication":  "Managed",
    "Capabilities":  "Email, OfficeCommunicationsOnline",
    "IsDefault":  "True",
    "IsInitial":  "True",
    "Name":  "curtisjmspartnerhotmail.onmicrosoft.com",
    "RootDomain":  "",
    "Status":  "Verified",
    "VerificationMethod":  "DnsRecord"
}

现在您看到了,枚举返回时带有上面的文本值(Status 和 VerificationMethod),而不是它们的整数值。

但是,这种方法有一些限制:

1) ConvertTo-Csv 不保留数组或复杂对象,并且 将它们作为类名输出(观看 ExtensionData 属性 在两个输出中)。在第二个输出中,我们倾向于丢失数据, 并获得类名 System.Runtime.Serialization.ExtensionDataObject 作为字符串

2) ConvertTo-Csv 和 ConvertFrom-Csv 都不是脚本级别的 命令行开关,但它们是命令级命令行开关,这意味着 我们不能在脚本结尾使用它们,但它们必须是 与我上面所做的单个命令一起使用。然而, ConvertTo-Json 不需要在 commmandLevel 应用,而只是 应用于脚本输出一次。

我的问题是:

1) 我如何仍然使用 convertTo-Json,以便我的所有枚举属性都返回其文本而不是整数,并且复杂对象或数组也不会丢失?在我使用的方法中,复杂的对象会丢失

2) 此外,它应该足够通用,以便它可以在脚本末尾应用,而不是在命令级别

【问题讨论】:

  • 不确定您所说的“脚本级”和“命令级”cmdlet 是什么意思;听起来您将某个概念不适当地应用于 PowerShell。如果您对此类概念有任何参考,请提供链接。
  • 这基本上是您之前问题的重复:stackoverflow.com/q/44494409/5771128
  • 您好,这完全不是重复的,因为它询问如何使用 convertTo-Json 保留复杂的对象。在我之前的问题中,我问过如何将 Enum 值保留为文本而不是整数。
  • 我在下面尝试了 cahvers 答案。没有运气,但是我随后尝试了这种方法,它似乎运作良好。 stackoverflow.com/a/54024450/491196

标签: json powershell csv enums


【解决方案1】:

ConvertTo-JsonConvertTo-Csv 都是以某种文本表示形式序列化对象的形式,并且在不同的用例中都有用。

ConvertTo-Csv 可能最适合用于可以在电子表格等表格中表达的二维数据。因此,尝试将“复杂”对象(即具有包含其他结构化数据的属性的对象)转换为简单表是很尴尬的。在这种情况下,PowerShell 将此类数据表示为数据类型的全名。

ConvertTo-Json 能够序列化更复杂的对象,因为该格式允许嵌套数组/数据结构,例如您示例中的 ExtensionData 属性。请注意,您可能需要使用-Depth 参数来确保正确序列化深度嵌套的数据。

所以问题真正归结为ConvertTo-Json cmdlet 如何序列化枚举,可以通过以下方式演示:

[PS]> (Get-Date).DayOfWeek
Tuesday

[PS]> (Get-Date).DayOfWeek.GetType()

IsPublic IsSerial Name      BaseType   
-------- -------- ----      --------   
True     True     DayOfWeek System.Enum

[PS]> Get-Date | Select DayOfWeek | ConvertTo-Json
{
    "DayOfWeek":  2
}

因此,在转换为 JSON 之前,您需要确保 DayOfWeek 属性(在此示例中)或 StatusVerificationMethod 属性(来自你的例子)首先转换为它们的字符串等价物。

您可以使用带有Select-Object 的表达式来执行此操作,以便在数据通过管道时对其进行转换。请注意,您确实需要包含 所有您希望包含在最终 JSON 中的属性:

[PS]> Get-Date |
  Select DateTime,@{Label="DayOfWeek";Expression={$_.DayOfWeek.ToString()}} |
  ConvertTo-Json
{
    "DateTime":  "13 June 2017 10:33:51",
    "DayOfWeek":  "Tuesday"
}

所以在你的情况下,你需要这样的东西:

[PS]> Get-Msoldomain |
  Select-Object ExtensionData,IsDefault,IsInitial,Name,RootDomain `
    ,{Label="Authentication";Expression={$_.Authentication.ToString()}} `
    ,{Label="Capabilities";Expression={$_.Capabilities.ToString()}} `
    ,{Label="Status";Expression={$_.Status.ToString()}} `
    ,{Label="VerificationMethod";Expression={$_.VerificationMethod.ToString()}} |
  ConvertTo-Json

【讨论】:

  • 对,但是我不想像您在此处使用 Select-Object 所做的那样列出特定属性。是否有通用的东西,可以自动对这些属性执行此操作,这样我就不必费心对属性进行预测。可以在我的 command-let 和 convertTo-Json 之间放置一些东西并对所有属性都适用?
  • 您可以提取对象的所有属性,检查是否是枚举并构建一个新对象,将这些枚举转换为字符串...将其发布为不同的答案。跨度>
【解决方案2】:

@puneet,在您对我的另一个答案发表评论之后,这是一个示例,说明您如何基于现有对象构建一个新对象,并将 Enum 类型转换为字符串。

这个想法是创建一个新的“空”对象,然后循环遍历原始对象的所有属性并将它们添加到新对象中,但如果任何原始属性是枚举,那么这些属性将转换为字符串。

$data = [PSCustomObject]@{}

(Get-Date).PSObject.Properties | Select Name,Value | Foreach-Object {
  if($_.Value.GetType().BaseType.FullName -eq "System.Enum"){
    $data | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value.ToString()
  }
  else {
    $data | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
  }
}

$data | ConvertTo-Json

您可能想为自己的应用程序稍微改进一下,但希望其背后的想法很清楚。一定要检查 JSON 输出中是否正确处理了所有属性。

【讨论】:

  • 循环“(Get-Date).PSObject.Properties”的方式,我不能对脚本中的每个命令都这样做。我的脚本将包含几个 command-let。我需要一种通用方式,以便它适用于整个脚本,并且不适用于命令行。
  • 换句话说,我想要一些适用于脚本输出的东西,而不是单个命令级别
  • 我仍然不清楚你的意思,我认为这是另一个问题的分支。我一直专注于在转换为 JSON 时如何将枚举序列化为字符串的狭隘问题。
  • 您可能需要使用更清楚地显示这一点的 MVCE (stackoverflow.com/help/mcve) 脚本提出新问题,因为听起来您可能需要帮助来创建重复执行此转换的函数和/或弄清楚如何编写脚本的输出等。
【解决方案3】:

要在将 psObject 转换为 json 时保留枚举、数组和日期,可以使用 newtonsoft。使用 Nerdy Mishka powershell 模块的示例https://github.com/chavers/powershell-newtonsoft

$obj = New-Object pscustomobject -Property @{Enum = (Get-DAte).DayOfWeek; int = 2; string = "du text"; array = @("un", "deux", "trois"); obj= @{enum = (Get-DAte).DayOfWeek; int = 2; string = "du text"; array = @("un", "deux", "trois")}}
Import-Module Fmg-PrettyJson
$settings = Get-NewtonsoftJsonSettings
$enumconv = "Newtonsoft.Json.Converters.StringEnumConverter"
$e = New-Object $enumconv
$settings.Converters.Add($e)
Set-NewtonsoftJsonSettings $settings
$obj | ConvertTo-NewtonsoftJson

返回:

{
  "array": [
    "un",
    "deux",
    "trois"
  ],
  "enum": "Thursday",
  "int": 2,
  "obj": {
    "enum": "Thursday",
    "array": [
      "un",
      "deux",
      "trois"
    ],
    "int": 2,
    "string": "du text"
  },
  "string": "du text"
}

【讨论】:

  • 我通过导入上述模块进行了尝试。当我针对上述命令“Get-Msoldomain |”运行它时ConvertTo-NewtonsoftJson' 它返回一个空对象 {}。知道会发生什么吗?
猜你喜欢
  • 2017-11-13
  • 2021-12-31
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 2021-09-04
  • 2018-08-18
  • 1970-01-01
  • 2015-03-20
相关资源
最近更新 更多