Search code examples
xmlpowershellscheduled-tasksinnertext

Difference between use ''#text'' and InnerText XML (Powershell)


I am working on updating some values inside an XML file and I am doing this using PowerShell. The XML file is an exported Scheduled Task definition and I am trying to update the value of the Command node, I want to change some part of the path to the program to execute and I am using this code:

 1-|[xml]$taskXmlDefinition = Get-Content -Path $pathXmlTaskDefinition
 2-|$oldCommand = $taskXmlDefinition.Task.Actions.Exec.Command
 3-|$programName = Split-Path -Leaf -Path $oldCommand
 4-|$newCommand =  Join-Path $newPath $programName
 5-|$taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = $newCommand
 6-|$newTaskXmlFilepath = (Join-Path $newPath $name)
 7-|$taskXmlDefinition.Save($newTaskXmlFilepath)

With that code, I am getting this error: enter image description here

The error is fixed if I change the line 5 for either one of this two:

 5-|$taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = $newCommand.ToString()

or

 5-|[string]($taskXmlDefinition.GetElementsByTagName("Command")[0].'#text') = $newCommand

But, I know that if I ask ($newCommand).GetType() The result will be System.String and there shouldn't be need to add .ToString()

I changed the line (5) for this code:

5-|$taskXmlDefinition.GetElementsByTagName("Command")[0].InnerText = $newCommand

and it's working fine. I don't understand the difference or what is going on that I need to make the cast to string explicit.

Can someone explain me the difference in this cases?


Solution

  • Seems to be related to this bug in PowerShell: XML nodes are too picky about setting values.

    Workaround (incomplete, choose any):

    $taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = "$newCommand"
    $taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = $newCommand.ToString()
    $taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = [string]$newCommand
    $taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = $newCommand.PSObject.BaseObject
    

    or apply any of above cast-like operations to $newCommand assignment e.g. as follows:

    $newCommand =  (Join-Path $newPath $programName).ToString()
    $taskXmlDefinition.GetElementsByTagName("Command")[0].'#text' = $newCommand