带双引号的Powershell ConvertTo-Json问题

时间:2019-09-18 23:33:06

标签: powershell

我正在尝试将文本文件转换为JSON格式的字符串,但是双引号没有正确定位。

我的 file.txt 包含以下结构化信息(开头两行也为空):

adapter_name : empty1 route_age : 10 route_nexthop : 172.0.0.1 route_protocol : NETMGMT1 speed : null

adapter_name : empty2 route_age : 100 route_nexthop : 172.0.0.2 route_protocol : NETMGMT2 speed : null

adapter_name : empty3 route_age : 1000 route_nexthop : 172.0.0.3 route_protocol : NETMGMT3 speed : null

我的代码是:

$data = Get-Content C:\scripts\file.txt | %{$_.PSObject.BaseObject}
$data | ConvertTo-Json 

没有这部分:

%{$_.PSObject.BaseObject}
它只是非常深入地下降到对象树中,这可能需要很长时间。

实际结果是:


    [
        "",
        "",
        "adapter_name          : empty1",
        "route_age             : 10",
        "route_nexthop         : 172.0.0.1",
        "route_protocol        : NETMGMT1",
        "speed                 : null "
        "",
        "adapter_name          : empty2",
        "route_age             : 100",
        "route_nexthop         : 172.0.0.2",
        "route_protocol        : NETMGMT2",
        "speed                 : null "
        "",
        "adapter_name          : empty3",
        "route_age             : 1000",
        "route_nexthop         : 172.0.0.3",
        "route_protocol        : NETMGMT3",
        "speed                 : null "
    ]

预期结果是:

[
  {
    "adapter_name"         : "empty1",
    "route_age"            : 10,
    "route_nexthop"        : "172.0.0.1",
    "route_protocol"       : "NETMGMT1",
    "speed"                : null
  },
  {
    "adapter_name"         : "empty2",
    "route_age"            : 100,
    "route_nexthop"        : "172.0.0.2",
    "route_protocol"       : "NETMGMT2",
    "speed"                : null
  },
  {
    "adapter_name"         : "empty3",
    "route_age"            : 1000,
    "route_nexthop"        : "172.0.0.3",
    "route_protocol"       : "NETMGMT3",
    "speed"                : null
  }
]

链接https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-6中的示例4和5显示了如何在类似情况下使用cmdlet ConvertoTo-Json ,但没有问题。

1 个答案:

答案 0 :(得分:1)

Get-Content仅从文本文件返回单独的行,它对这些行中可能编码的任何结构一无所知。

因此,您只是将行直接转换为JSON,这将导致您看到的JSON字符串值的平面列表。

要解决该问题,必须将文本文件自己解析为结构化对象(哈希表),然后逐块进行,然后将其传递给ConvertTo-Json

# Read the input file as a whole (-Raw) and split it into blocks (paragraphs)
(Get-Content -Raw C:\scripts\file.txt) -split '\r?\n\r?\n' -ne '' |
  ForEach-Object { # Process each block
    # Initialize an ordered hashtable for the key-values pairs in this block.
    $oht = [ordered] @{}
    # Loop over the block's lines.
    foreach ($line in $_ -split '\r?\n' -ne '') {
      # Split the line into key and value...
      $key, $val = $line -split ':', 2
      # ... and add them to the hashtable.
      $oht[$key.Trim()] = $val.Trim()
    }
    $oht # Output the hashtable.
  } | ConvertTo-Json

以上内容会产生所需的输出。


顺便说一句,重新:

  

没有这部分:
  %{$_.PSObject.BaseObject}
  它只是非常深入地下降到对象树中,这可能需要很长时间。

问题是Get-Content用其他通常不可见的属性来修饰其输出的行,这些属性提供了原始信息,例如从中读取行的文件的路径。

在序列化方案中,例如使用ConvertTo-Json时,这些通常隐藏的属性意外出现。

上面的解决方案隐式绕过了这个问题,因为在处理过程中会创建 new 字符串。

虽然其他属性可能有用,但通常不仅不需要它们,而且会降低Get-Content的速度。

  • This GitHub issue建议向Get-Content添加一个开关,以允许退出装饰线条(自PowerShell Core 7.0.0-preview起未实现)。 3)

  • 互补地,this GitHub issue建议忽略与原始JSON类型相对应的类型(包括[string](自PowerShell Core 7.0.0-preview起未实现)的类型的PowerShell添加的属性。 3)