【问题标题】:Serialization differences between PowerShell's Format-List and ConvertTo-JsonPowerShell 的 Format-List 和 ConvertTo-Json 的序列化差异
【发布时间】:2021-12-28 00:03:32
【问题描述】:

我正在尝试在 Python 中解析 PowerShell 的 Get-NetIPConfiguration 的结果。

结果包含我想要的默认格式(格式列表)中的值,但在转换为 JSON 时不包含,这是我想要使用的格式。

注意DNSServer是如何被Format-List序列化的:

PS C:\Users\BoppreH> Get-NetIPConfiguration | Format-List
InterfaceAlias       : VirtualBox Host-Only Network
InterfaceIndex       : 23
InterfaceDescription : VirtualBox Host-Only Ethernet Adapter
IPv4Address          : 192.168.56.1
IPv6DefaultGateway   :
IPv4DefaultGateway   :
DNSServer            : fec0:0:0:ffff::1
                       fec0:0:0:ffff::2
                       fec0:0:0:ffff::3

[...]

ConvertTo-Json -Depth 1 以不同的方式序列化 DNSServer 属性(以完全无用的方式):

PS C:\Users\BoppreH> Get-NetIPConfiguration | ConvertTo-Json -Depth 1
[
    {
        "Detailed":  false,
        "ComputerName":  "BOPPREH-DESKTOP",
        "InterfaceAlias":  "VirtualBox Host-Only Network",
        "InterfaceIndex":  23,
        "InterfaceDescription":  "VirtualBox Host-Only Ethernet Adapter",
        "CompartmentId":  1,
        "NetAdapter":  "MSFT_NetAdapter (CreationClassName = \"MSFT_NetAdapter\", DeviceID = \"{EAF79493-7C78-44D2-ADB4-F3EF196D2F49}\", SystemCreationClassName = \"CIM_NetworkPort\", SystemName = \"boppreh-desktop\")",
        "NetCompartment":  "MSFT_NetCompartment (InstanceID = \";55;\")",
        "NetIPv6Interface":  "MSFT_NetIPInterface (Name = \"??55??55;\", CreationClassName = \"\", SystemCreationClassName = \"\", SystemName = \"\")",
        "NetIPv4Interface":  "MSFT_NetIPInterface (Name = \"??55?55;\", CreationClassName = \"\", SystemCreationClassName = \"\", SystemName = \"\")",
        "NetProfile":  null,
        "AllIPAddresses":  "192.168.56.1 fe80::d83f:9609:86ff:2b57%23",
        "IPv6Address":  "",
        "IPv6TemporaryAddress":  "",
        "IPv6LinkLocalAddress":  "fe80::d83f:9609:86ff:2b57%23",
        "IPv4Address":  "192.168.56.1",
        "IPv6DefaultGateway":  null,
        "IPv4DefaultGateway":  null,
        "DNSServer":  "MSFT_DNSClientServerAddress (Name = \"23\", CreationClassName = \"\", SystemCreationClassName = \"\", SystemName = \"23\") MSFT_DNSClientServerAddress (Name = \"23\", CreationClassName = \"\", SystemCreationClassName = \"\", SystemName = \"2\")"
    },
[...]

直到深度级别 4,地址才变得可见,但到那时,输出会大几倍,并且更难导航。

我目前的替代方法是将结果通过管道传输到 Select-Object 并使用计算的属性自己转换值(在 DNSServer 的情况下是 $_.DNSServer.ServerAddresses -join " "),但这对于每个属性来说都很麻烦,并且会使其他属性序列化也不一样。

如何强制 JSON 序列化程序像列表格式化程序一样格式化值?

【问题讨论】:

  • 这个序列化问题,加上从 Python 调用 PowerShell 时的 2.5 秒延迟,以及缺少网络掩码信息,让我不得不切换到手动解析 ipconfig /all,这可耻。

标签: json powershell serialization json-deserialization


【解决方案1】:

注意DNSServer是如何被Format-List序列化的

Format-* cmdlet 不会序列化,它们使用 PowerShell 的 output-formatting system(而不是 serialization infrastructure)生成用于显示的字符串表示形式

这些表示不是用于程序化处理,但如果你确实想将它们作为字符串处理,你可以通过管道他们给Out-String

# Returns a single-line string; add -Stream to get an array of lines.
# Add -Width to explicitly specify a line width (console window width is the default).
# Note: Since Format-List is used for formatting *by default*, 
#       you don't strictly need the Format-List here.
#       Alternatively, use Format-Table for a *table* representation
$stringRep = Get-NetIPConfiguration | Format-List | Out-String

如何强制 JSON 序列化程序像列表格式化程序一样格式化值?

您唯一的选择确实是通过构造您自己的[pscustomobject] 实例来简化对象图,例如通过Select-Object 和计算属性,或在ForEach-Object 循环中使用[pscustomobject] 文字(例如
[pscustomobject] @{ foo = 'bar'; baz = 'quux' })。

例如:

Get-NetIPConfiguration | ForEach-Object {
  [pscustomobject] @{
    InterfaceAlias = $_.InterfaceAlias
    InterfaceIndex = $_.InterfaceIndex
    InterfaceDescription = $_.InterfaceDescription
    'NetProfile.Name' = $_.NetProfile.Name
    IPv4Address = $_.IPv4Address -join "`n"
    IPv6DefaultGateway = $_.IPv6DefaultGateway.NextHop
    IPv4DefaultGateway = $_.IPv4DefaultGateway.NextHop
  }
}

将上述内容传递给ConvertTo-Json 给出了合理的表示。

请注意,Get-NetIPConfigurationformatting data 内置了额外的逻辑,该逻辑会根据适配器类型在其显示表示中改变输出字段,上面没有考虑到这一点.

【讨论】:

  • 不幸的是,这需要为每个成员自定义表达式,例如$_.IPv4DefaultGateway.NextHop 用于默认网关地址,$_.DNSServer.ServerAddresses -join " " 用于 DNS 服务器。没有办法像在表格视图中一样格式化成员吗?我尝试了Out-String.ToString(),它们都给出了不同的(和无用的)表示。
  • @BoppreH,如果您想要表格视图,请通过管道发送至 Format-Table | Out-String - 请参阅我的更新。通常,Out-String 为您提供与控制台中相同的表示形式,即多行字符串 - 或者,-Stream - 作为行数组。您可以在有或没有前面显式的 Format-* cmdlet 调用的情况下使用它。
  • “表格/列表视图”是指单个 字段 在表格中的格式,而不是表格本身作为大字符串的方式。我基本上是在寻找 Format-List 给我的相同数据,但在 JSON 中。无论如何,您在“ForEach-Object”示例中完成了大部分艰苦的工作,所以我接受了答案。谢谢。
猜你喜欢
  • 2015-03-20
  • 2015-05-25
  • 2021-12-31
  • 2018-08-18
  • 1970-01-01
  • 2016-04-26
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多