Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change XML Element value with PowerShell

I'm only finding stuff on how to change the attribute values of a XML element here on StackOverflow.

But how do we change the value of the element itself using PowerShell?

I currently have:

XML

<Task>
  <Settings>
  ...
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>blablabla</Command>
      <Arguments>CHANGETHISVALUE</Arguments>
    </Exec>
  </Actions>
</Task>

SCRIPT

$filePathToTask = C:\Task.xml
$xml = New-Object XML
$xml.Load($filePathToTask)
$element =  $xml.SelectSingleNode("//Arguments")
$element.InnerText("newtext")
$xml.Save($filePathToTask)

However, I can't seem to use methods on the last variable. What am I doing wrong?

Edit

  • Added code

The error that I'm getting is You cannot call a method on a null-valued expression

I think my problem lies at:

$ElementToChange =  $xml.SelectSingleNode("//Arguments")

Which stays null, but I have tried methods like .SelectNodes and playing around with the //Argumentstag but still no success

like image 584
Kahn Kah Avatar asked Mar 09 '17 15:03

Kahn Kah


Video Answer


2 Answers

InnerText is a property, not a method. It's used like this:

$element.InnerText = "newtext"

Also, I suspect that your original data (unlike the XML sample you posted) uses namespaces. AFAICS that's the only possible reason why $xml.SelectSingleNode('//Arguments') would return an empty result. XML files exported from the Windows Task Scheduler definitely are namespaced:

<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task‌​">
  <!-- ... -->
</Task>

Namespaces are not like other node attributes and affect not only the node itself, but also its child nodes. For selecting nodes from an XML with namespaces you need a namespace manager:

$nsm = New-Object Xml.XmlNamespaceManager($xml.NameTable)
$nsm.AddNamespace('ns', $xml.DocumentElement.NamespaceURI)
$element = $xml.SelectSingleNode('//ns:Arguments', $nsm)
like image 54
Ansgar Wiechers Avatar answered Sep 25 '22 20:09

Ansgar Wiechers


When I run:

$filePathToTask = "C:\temp\Task.xml"
$xml = New-Object XML
$xml.Load($filePathToTask)
$element =  $xml.SelectSingleNode("//Arguments")
$element.InnerText = "New Text"
$xml.Save($filePathToTask)

And re-check the output, I do see the updated value:

<Task>
  <Settings>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>blablabla</Command>
      <Arguments>New Text</Arguments>
    </Exec>
  </Actions>
</Task>

I enclosed the path in quotes, otherwise I was getting an error on the load line. That's good practice anyway, since the parameter for the Load method takes string filepath as input. Then as Ansgar mentions, use the assignment operator ("=") to set the new value in memory, then dump to file.

like image 9
Dave_J Avatar answered Sep 25 '22 20:09

Dave_J