构建一个脚本以将XML文件转换为JSON(具有特定格式)

时间:2015-12-10 15:43:41

标签: json xml powershell

我正在编写一个脚本,将XML输出文件转换为具有特定格式的JSON文件。下面是要转换的XML输出。我在完成这项任务时遇到了问题,并且我在问底部脚本的哪些更改可以实现这一目标?

来自output.xml的片段:

<System>
<tools>
<tool_PSList>
<process>
<process>
<pid>4188</pid>
<ownersid>"S-1-5-21-3556032652-3399990904-2739522603-1001"</ownersid>
<ownername>"Bochm"</ownername>
<ownerdomain>"DESKTOP-LS0HCH3"</ownerdomain>
-<file>
<name>"C:\ProgramFiles\WindowsApps\Microsoft.Messaging_1.10.22012.0_x86__8wekyb3d8bbwe\SkypeHost.exe"</name>
<size>44032</size>
<attr str="ARCHIVE" hex="0x20"/>
<cert_exists>"FALSE"</cert_exists>
<cert_verified>"FALSE"</cert_verified>
<cert_result>"TRUST_E_NOSIGNATURE"</cert_result>
<cert_comment>"The file is not signed"</cert_comment>

JSON输出所需的格式如下所示(idealoutput.json,时间戳替换为脚本运行的时间):

{
"os":  "win",
"ts":  "timestamp here",
"value":  "C:\\Program Files\\WindowsApps\\Microsoft.Messaging_1.10.22012.0_x86__8wekyb3d8bbwe\\SkypeHost.exe\"; cert_comment=\"The file is not signed\"
}

下面是我在当前状态下生成的当前脚本,不幸的是,这是我第一周使用PowerShell,XML和JSON。我可以包含下面我脚本中提到的其他文件,但我猜测有一种比导入格式更简单的方法,然后尝试用输出文件修改它,所以我没有在这里列出它。如果你想看到下面提到的其他XML文件,请告诉我,我很乐意帮忙。任何见解或建议将不胜感激!

#Puts output of crowdresponse in $xml
$xml = [xml](Get-Content -Path C:\Users\Bochm\Downloads\CrowdResponse\output.xml)

#Puts the formating in $format
$format = [xml](Get-Content -Path C:\Users\Bochm\Downloads\CrowdResponse\format.xml)

#Filters the output of crowdresponse into results 
$result = $xml.system.tools.tool_PSList.processes.process.file |
          Select-Object name, cert_comment

#adds the mac address to result
$result += $xml.system | Select-Object macv4

$cert_valid = $xml.system.tools.tool_PSList.processes.process.file | Where-Object {
    $_.cert_signer -notmatch "Microsoft Corporation" -and
    $_.cert_signer -notmatch "Microsoft Windows" -and
    $_.cert_comment -match "The file is signed and the signature was verified"
} | Select-Object name, cert_comment  

$cert_invalid = $xml.system.tools.tool_PSList.processes.process.file |
    Where-Object { $_.cert_comment -match "The file is not signed" } |
    Select-Object name, cert_comment  

$node.innerXml += $cert_invalid.innerXml | Select-Object name, cert_comment

$result | ConvertTo-Json |
    Out-File "C:\Users\Bochm\Downloads\CrowdResponse\output.json"
$cert_valid | ConvertTo-Json |
    Out-File "C:\Users\Bochm\Downloads\CrowdResponse\certs_valid.json"
$cert_invalid | ConvertTo-Json |
    Out-File "C:\Users\Bochm\Downloads\CrowdResponse\certs_invalid.json"
$node | Select-Object os, ts, value, 'text' | ConvertTo-Json |
    Out-File "C:\Users\Bochm\Downloads\CrowdResponse\format.json"

后续问题代码:

$name = $xml.SelectNodes('//file') | ForEach-Object {
          $_.cert_signer -notmatch  "Microsoft Corporation" -and
          $_.cert_signer -notmatch "Microsoft Windows" -and
          $_.cert_comment -match "The file is signed and the signature was verified"
        } | Select-Object cert_comment

$name = $xml.system.tools.tool_PSList.processes.process.file |
        SelectNodes('//file') |
        ForEach-Object {
          $_.cert_signer -notmatch "Microsoft Corporation" -and
          $_.cert_signer -notmatch "Microsoft Windows" -and
          $_.cert_comment -match "The file is signed and the signature was verified"
        } | Select-Object name

希望最终问题的代码:

$xml = Get-Content 'C:\Users\Bochm\Downloads\CrowdResponse\output.xml'

$name = $xml.system.tools.tool_PSList.processes.process.file| Where-Object {
   $_.cert_signer -notmatch  "Microsoft Corporation" -and
   $_.cert_signer -notmatch "Microsoft Windows" -and
   $_.cert_comment -match "The file is signed and the signature was verified"
 } | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | Select-Object name 
#$name    = $xml.SelectSingleNode('//name').'#text'
$name = $xml.system.tools.tool_PSList.processes.process.file | Where-Object {
   $_.cert_signer -notmatch  "Microsoft Corporation" -and
   $_.cert_signer -notmatch "Microsoft Windows" -and
   $_.cert_comment -match "The file is signed and the signature was verified"
 } | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | Select-Object cert_comment 

$name = $xml.system.tools.tool_PSList.processes.process.file | Where-Object {
   $_.cert_signer -notmatch  "Microsoft Corporation" -and
   $_.cert_signer -notmatch "Microsoft Windows" -and
   $_.cert_comment -match "The file is signed and the signature was verified"
 } | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | Select-Object name 

$name = $xml.system.tools.tool_PSList.processes.process.file| Where-Object {
   $_.cert_comment -match "The file is not signed"
 } | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | Select-Object cert_comment 

$name = $xml.system.tools.tool_PSList.processes.process.file| Where-Object {
   $_.cert_comment -match "The file is not signed"
 } | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | Select-Object name 
#$name    = $xml.SelectSingleNode('//name').'#text'

#$comment = $xml.SelectSingleNode('//cert_comment').'#text'

$prop = [ordered]@{
  'os'    = 'win'
  'ts'    = (Get-Date).DateTime
  'value' = "$name; cert_comment=$comment"
}

New-Object -Type PSCustomObject -Property $prop |  ConvertTo-Json | Out-File "C:\Users\Bochm\Downloads\CrowdResponse\end.json"

1 个答案:

答案 0 :(得分:2)

我仍然不太清楚所需的转换是什么,因为您的XML示例格式不正确,输出JSON的3个属性中的2个似乎没有出现在其中。

假设你要提取<name><cert_comment>节点的内容并用OS和时间戳丰富它,你可以这样做:

[xml]$xml = Get-Content 'C:\path\to\output.xml'

$name    = $xml.SelectSingleNode('//name').'#text'
$comment = $xml.SelectSingleNode('//cert_comment').'#text'

$prop = [ordered]@{
  'os'    = 'win'
  'ts'    = (Get-Date).DateTime
  'value' = "$name; cert_comment=$comment"
}

New-Object -Type PSCustomObject -Property $prop | ConvertTo-Json

修改

$name = $xml.SelectNodes('//file') | ForEach-Object {
          $_.cert_signer -notmatch  "Microsoft Corporation" -and
          $_.cert_signer -notmatch "Microsoft Windows" -and
          $_.cert_comment -match "The file is signed and the signature was verified"
        } | Select-Object cert_comment

$name = $xml.system.tools.tool_PSList.processes.process.file |
        SelectNodes('//file') |
        ForEach-Object {
          $_.cert_signer -notmatch "Microsoft Corporation" -and
          $_.cert_signer -notmatch "Microsoft Windows" -and
          $_.cert_comment -match "The file is signed and the signature was verified"
        } | Select-Object name

这两个代码段不起作用。要过滤您需要Where-Object的对象列表,而不是ForEach-Object

 ... | Where-Object {
   $_.cert_signer -notmatch  "Microsoft Corporation" -and
   $_.cert_signer -notmatch "Microsoft Windows" -and
   $_.cert_comment -match "The file is signed and the signature was verified"
 } | ...

另外,您不想为$name分配评论列表,但要创建自定义对象列表,因此您需要在ForEach-Object循环中创建对象放在过滤器后面:

... | ForEach-Object {
  $prop = [ordered]@{
    'os'    = 'win'
    'ts'    = (Get-Date).DateTime
    'value' = "{0}; cert_comment={1}" -f $_.name, $_.cert_comment
  }
  New-Object -Type PSCustomObject -Property $prop
} | ...