Question

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?
Was it helpful?

Solution

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);

OTHER TIPS

Why not use PowerCLI?

New-NetworkAdapter -VM $vm -NetworkName "VM Network" -MacAddress  'aa:bb:cc:dd:ee:ff' -WakeOnLan -StartConnected
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top