【问题标题】:How do I reformat an existing XML document with PowerShell如何使用 PowerShell 重新格式化现有 XML 文档
【发布时间】:2021-07-29 14:30:48
【问题描述】:

我正在尝试从这里更新一个 XML 文档:

<Enclave id="OLD">
    <device>
        <name>MGMT</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
</Enclave>

<Enclave id="NEW">
    
    <device>
        <name>G-VDS-GooD</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC001</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC002</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
</Enclave>

到这里:

<Enclave id="OLD">
    <device>
        <name>MGMT</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
</Enclave>

<Enclave id="NEW">
    
    <device>
        <name>G-VDS-GooD</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC001</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <cert>
             <inform>PEM</inform>
             <outform>PEM</outform>
             <name>G-VDS-ENC001</name>
             <type>WEBServer</type>
             <pwd>Password</pwd>
             <altSubject />
        </cert>
        <RequireCert>1</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC002</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <cert>
             <inform>PEM</inform>
             <outform>PEM</outform>
             <name>G-VDS-ENC002</name>
             <type>WEBServer</type>
             <pwd>Password</pwd>
             <altSubject />
        </cert>
        <RequireCert>1</RequireCert>
    </device>
</Enclave>

我已经编写了一些 PowerShell 命令(见下文),但只能做到这一点:

<Enclave id="OLD">
    <device>
        <name>MGMT</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
</Enclave>

<Enclave id="NEW">
    
    <device>
        <name>G-VDS-GooD</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <inform>PEM</inform>
        <outform>PEM</outform>
        <RequireCert>0</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC001</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <cert>
             <inform>PEM</inform>
             <outform>PEM</outform>
             <type>WEBServer</type>
             <pwd>Password</pwd>
             <altSubject />
        </cert>
        <RequireCert>0</RequireCert>
    </device>
    <device>
        <name>G-VDS-ENC002</name>
        <type>VoIP</type>
        <vlan>Voice2Network</vlan>
        <cert>
             <inform>PEM</inform>
             <outform>PEM</outform>
             <type>WEBServer</type>
             <pwd>Password</pwd>
             <altSubject />
        </cert>
        <RequireCert>1</RequireCert>
        <RequireCert>0</RequireCert>
    </device>
</Enclave>

这是我的 PowerShell 代码:

$LoadType = "NEW"
$FileName = "C:\Voip.xml"
[xml]$FileOriginal = Get-Content $FileName
$Pattern = $FileOriginal.SelectNodes("/Configuration/Enclave[@id = `"$LoadType`"]/device[name[contains(text(), 'G-VDS-ENC')]]")

foreach($Pat in $Pattern) {
    $inform = $FileOriginal.SelectSingleNode("/Configuration/Enclave[@id = `"$LoadType`"]/device[name[contains(text(), 'G-VDS-ENC')]]/inform")
    $inform.ParentNode.RemoveChild($inform) | Out-Null

    $outform = $FileOriginal.SelectSingleNode("/Configuration/Enclave[@id = `"$LoadType`"]/device[name[contains(text(), 'G-VDS-ENC')]]/outform")
    $outform.ParentNode.RemoveChild($outform) | Out-Null

    $RequireCert = $FileOriginal.SelectSingleNode("/Configuration/Enclave[@id = `"$LoadType`"]/device[name[contains(text(), 'G-VDS-ENC')]]/RequireCert")
    $RequireCert.ParentNode.RemoveChild($RequireCert) | Out-Null

    # Create cert element 
    $cert = $FileOriginal.CreateElement('cert')

    $newinform = $FileOriginal.CreateElement('inform')
    $newinform.InnerText = 'PEM'

    $newoutform = $FileOriginal.CreateElement('outform')
    $newoutform.InnerText = 'PEM'

    $type = $FileOriginal.CreateElement('type')
    $type.InnerText = 'WebServer'

    $pwd = $FileOriginal.CreateElement('pwd')
    $pwd.InnerText = 'password'

    $altSubject = $FileOriginal.CreateElement('altSubject')

    $cert.AppendChild($newinform)
    $cert.AppendChild($newoutform)
    #$cert.AppendChild($name)
    $cert.AppendChild($type)
    $cert.AppendChild($pwd)
    $cert.AppendChild($altSubject)

    # Insert cert element after 'vlan' element
    $Pat.InsertAfter( $cert, $Pat.SelectSingleNode('vlan') ) 

    $newRequireCert = $FileOriginal.CreateElement('RequireCert')
    $newRequireCert.InnerText = "1"
    $Pat.InsertAfter( $newRequireCert, $Pat.SelectSingleNode('cert') )
}

$FileOriginal.Save($FileName)

我无法让“RequireCert”节点在 G-VDS-ENC001 和 G-VDS-ENC002 节点中以 1 属性正确显示。此外,我想不出任何关于如何将 G-VDS-ENC001 和 G-VDS-ENC002 节点元素克隆或复制到新创建的 Cert 节点的语法。谁能帮我弄清楚还需要什么或检查我糟糕的 PowerShell 代码。

【问题讨论】:

    标签: powershell clone


    【解决方案1】:

    您可以更新现有的RequireCert 节点,而不是删除+重新创建它:

    # Select the node
    $RequireCert = $FileOriginal.SelectSingleNode("/Configuration/Enclave[@id = `"$LoadType`"]/device[name[contains(text(), 'G-VDS-ENC')]]/RequireCert")
    # Set the node's text value
    $RequireCert.'#Text' = 1
    

    然后您可以删除当前代码中的$newRequireCert 部分。

    【讨论】:

    • 感谢您的帮助。因此,这确实会导致 G-VDS-ENC001 设备上的 RequireCert 节点正确更新,但设备 G-VDS-ENC002 上的 RequireCert 节点仍未更新。
    • @shakex 哎呀!只需将设备名称过滤器从 'G-VDS-ENC' 更新为 'G-VDS-ENC002'contains() 过滤器表示两者都匹配,并且它正在选择第一个。
    【解决方案2】:

    我同意Cpt.Whale,您无需删除并重新创建 RequireCert 节点。

    使用点表示法,您可以像这样更新这些节点:

    (($FileOriginal.Configuration.Enclave | Where-Object { $_.id -eq $LoadType }).device | 
      Where-Object { $_.name -like 'G-VDS-ENC*' }) | ForEach-Object { $_.RequireCert = '1' }
    

    【讨论】:

      猜你喜欢
      • 2013-11-12
      • 2016-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      相关资源
      最近更新 更多