简体   繁体   中英

Powershell: Adding element to an XML document with Namespaces

I'm attempting to write a powershell cmdlet that uses VMWare's vcloud REST API to add a NIC (something that VMWare's own powerCLI doesn't seem to allow). In order to do that, I need to take this XML:

<?xml version="1.0" encoding="UTF-8"?><vcloud:RasdItemsList
    xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
    xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    href="https://vcloud.example.com/api/vApp/vm-89c84bd6-c6f2-4e4c-8a7d-c44a3489e2e4/virtualHardwareSection/networkCards"
    type="application/vnd.vmware.vcloud.rasdItemsList+xml">
    <vcloud:Link
        href="https://vcloud.example.com/api/vApp/vm-89c84bd6-c6f2-4e4c-8a7d-c44a3489e2e4/virtualHardwareSection/networkCards"
        rel="edit"
        type="application/vnd.vmware.vcloud.rasdItemsList+xml"/>
</vcloud:RasdItemsList>

And add in the following element below the last vcloud:Link.

    <ovf:Item>
        <rasd:Address></rasd:Address>
        <rasd:AddressOnParent>0</rasd:AddressOnParent>
        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
        <rasd:Connection
            vcloud:ipAddressingMode="none"
            vcloud:primaryNetworkConnection="true">VM Network</rasd:Connection>
        <rasd:Description>E1000 ethernet adapter on "VM Network"</rasd:Description>
        <rasd:ElementName>Network adapter 0</rasd:ElementName>
        <rasd:InstanceID>1</rasd:InstanceID>
        <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
        <rasd:ResourceType>10</rasd:ResourceType>
    </ovf:Item>

Now, I've got the original XML into PS as $xmlDoc, and I have tried the code below:

$xmlElt = $xmlDoc.CreateElement("ovf:Item")
$xmlSubElt = $xmlDoc.CreateElement("rasd:Address")
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:AddressOnParent")
$xmlSubText = $xmlDoc.CreateTextNode("0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:AutomaticAllocation")
$xmlSubText = $xmlDoc.CreateTextNode("false")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:Connection")
$xmlSubText = $xmlDoc.CreateTextNode("none")
$xmlSubElt.AppendChild($xmlSubText)
$xmlAtt = $xmlDoc.CreateAttribute("vcloud:primaryNetworkConnection")
$xmlAtt.Value = "True"
$xmlSubElt.Attributes.Append($xmlAtt)
$xmlAtt = $xmlDoc.CreateAttribute("vcloud:ipAddressingMode")
$xmlAtt.Value = "NONE"
$xmlSubElt.Attributes.Append($xmlAtt)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:Description")
$xmlSubText = $xmlDoc.CreateTextNode("Network Adapter 0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ElementName")
$xmlSubText = $xmlDoc.CreateTextNode("Network Adapter 0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:InstanceID")
$xmlSubText = $xmlDoc.CreateTextNode("0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ResourceSubType")
$xmlSubText = $xmlDoc.CreateTextNode("E1000")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ResourceType")
$xmlSubText = $xmlDoc.CreateTextNode("10")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlDoc.LastChild.AppendChild($xmlElt);

Here's the relevant bit of the XML that this creates though:

<Item>
  <Address />
  <AddressOnParent>0</AddressOnParent>
  <AutomaticAllocation>false</AutomaticAllocation>
  <Connection primaryNetworkConnection="True" ipAddressingMode="NONE">none</Connection>
  <Description>Network Adapter 0</Description>
  <ElementName>Network Adapter 0</ElementName>
  <InstanceID>0</InstanceID>
  <ResourceSubType>E1000</ResourceSubType>
  <ResourceType>10</ResourceType>
</Item>

As you can see, it mostly works, but it unfortunately seems to be removing the XML Namespace prefixes. It may still work, but I'd really like to match the format. I'm pretty new to XML and Powershell interactions, so my questions are these:

  1. How do I make it output the namespaces?
  2. Is there an easier way that manually creating each element like this that I'm just stupidly overlooking?

Solved my own problem. I needed to load in the namespaces from the "rasdItemsList" xpath into a System.Xml.XmlNamespaceManager, then lookup the URI's for each when creating the elements.

$nsm = New-Object System.Xml.XmlNamespaceManager($xmldoc.nametable)
$nsm.addnamespace("xsi", $xmldoc.rasdItemsList.GetNamespaceOfPrefix("xsi"))
$nsm.addnamespace("rasd", $xmldoc.rasdItemsList.GetNamespaceOfPrefix("rasd"))
$nsm.addnamespace("vcloud", $xmldoc.rasdItemsList.GetNamespaceOfPrefix("vcloud"))

$xmlElt = $xmlDoc.CreateElement("vcloud:Item", $nsm.LookupNamespace("vcloud"))
$xmlSubElt = $xmlDoc.CreateElement("rasd:Address", $nsm.LookupNamespace("rasd"))
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:AddressOnParent", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:AutomaticAllocation", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("false")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:Connection", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("none")
$xmlSubElt.AppendChild($xmlSubText)
$xmlAtt = $xmlDoc.CreateAttribute("vcloud:primaryNetworkConnection", $nsm.LookupNamespace("vcloud"))
$xmlAtt.Value = "True"
$xmlSubElt.Attributes.Append($xmlAtt)
$xmlAtt = $xmlDoc.CreateAttribute("vcloud:ipAddressingMode", $nsm.LookupNamespace("vcloud"))
$xmlAtt.Value = "NONE"
$xmlSubElt.Attributes.Append($xmlAtt)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:Description", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("Network Adapter 0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ElementName", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("Network Adapter 0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:InstanceID", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("0")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ResourceSubType", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("E1000")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlSubElt = $xmlDoc.CreateElement("rasd:ResourceType", $nsm.LookupNamespace("rasd"))
$xmlSubText = $xmlDoc.CreateTextNode("10")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
$xmlDoc.LastChild.AppendChild($xmlElt);

为什么不使用PowerCLI?

New-NetworkAdapter -VM $vm -NetworkName "VM Network" -MacAddress  'aa:bb:cc:dd:ee:ff' -WakeOnLan -StartConnected

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM