Search code examples
xmlpowershellxml-rpc

Powershell, xml and xmlrpc


So, I'm writing a script to do some simple xmlrpc requests. As far as I can tell Powershell doesn't have anything built in, so the best and simplest solution I've found is to simply create the xml and post it using invoke-webrequest or invoke-restmethod.

If someone knows of a better way with out of the box functionality, feel free to educate me.

Now, here's the part I'm having some trouble with. Generating the xml. How I would like it to work: create a custom object, add properties, convert to xml and post. Even better would be to create an xml-object, add nodes and properties and then post it.

This appears to be a bit of a PITA though, and at this point I feel it will be easier to treat the xml as a string in Powershell and edit/manage it that way. So, am I missing something or is working with xml in Powershell not as easy as I had hoped?

Edit: To clarify, I'm asking for the best tool/technique to create custom xml in Powershell. So far my impression is that the best way is to simply build it as a string, as using the built in xml tools is cumbersume and messy. However I realize this would not be viable for larger or more complex XML-structures.

What I have so far, which doesn't work and isn't as pretty as I'd like. This code gives me the following error

Method invocation failed because [System.String] does not contain a method named 'Appendchild'.

$xmlreq = [xml]@'
<?xml version="1.0"?>
<methodCall>
<methodName>methodname</methodName>
</methodCall>
'@

$child = $xmlreq.CreateElement("params")
$xmlreq.methodCall.Appendchild($child)
$child = $xmlreq.CreateElement("param")
$xmlreq.methodCall.params.Appendchild($child)
$child = $xmlreq.CreateElement("value")
$xmlreq.methodCall.params.param.Appendchild($child)
$child = $xmlreq.CreateElement("string")
$xmlreq.methodCall.params.param.value.Appendchild($child)
$xmlreq.methodCall.params.param.value.string = "value"

What the resulting XML should look like:

<?xml version="1.0"?>
<methodCall>
<methodName>methodname</methodName>
<params>
<param>
<value>
<string>param1</string>
</value>
</param>
<param>
<value>
<string>param2</string>
</value>
</param>
<param>
<value>
<string>param3</string>
</value>
</param>
<param>
<value>
<string>param4</string>
</value>
</param>
<param>
<value>
<struct>
<member>
<name>property1</name>
<value>
<int>0</int>
</value>
</member>
<member>
<name>property2</name>
<value>
<string>value</string>
</value>
</member>
<member>
<name>property3</name>
<value>
<int>1</int>
</value>
</member>
<member>
<name>property4</name>
<value>
<string>value</string>
</value>
</member>
<member>
<name>property5</name>
<value>
<int>2</int>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>

Solution

  • Try something like this to build your tree:

    [xml]$doc = @'
    <?xml version="1.0"?>
    <methodCall>
    <methodName>methodname</methodName>
    </methodCall>
    '@
    
    $node1 = $doc.CreateElement('params')
    $node2 = $doc.CreateElement('param')
    $node3 = $doc.CreateElement('value')
    $node4 = $doc.CreateElement('string')
    
    $node4.set_innertext('param1')
    $node3.AppendChild($node4)
    $node2.AppendChild($node3)
    $node1.AppendChild($node2)
    
    $node2 = $doc.CreateElement('param')
    $node3 = $doc.CreateElement('value')
    $node4 = $doc.CreateElement('string')
    
    $node4.set_innertext('param2')
    $node3.AppendChild($node4)
    $node2.AppendChild($node3)
    
    $node1.AppendChild($node2)
    
    $doc.methodCall.AppendChild($node1)
    
    $doc.Save("$(pwd)\foo.xml")
    cat .\foo.xml
    

    This is just a quick and dirty example to demonstrate a point. You'll need to polish this up for your needs. I did the following:

    • Move the xml type declaration to the variable and not the string.
    • Built the tree first then added it to the document

    Hope this helps!