Kahn Kah
Kahn Kah

Reputation: 1453

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

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

Upvotes: 21

Views: 74406

Answers (2)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200193

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)

Upvotes: 33

Dave_J
Dave_J

Reputation: 408

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.

Upvotes: 10

Related Questions