21

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

Kahn Kah
  • 1,389
  • 7
  • 24
  • 49
  • If you want us to tell you what you're doing wrong, you need to tell us what yo *do.* And what error that produces. – Ansgar Wiechers Mar 09 '17 at 16:15
  • I'm sorry @AnsgarWiechers , I thought my mistake was maybe obvious by only the code (like usual when I post something) but you're right, I will edit it now – Kahn Kah Mar 09 '17 at 16:16

2 Answers2

33

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)
Community
  • 1
  • 1
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
10

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.

Dave_J
  • 408
  • 9
  • 17