0

Context is PowerShell, Register-ScheduledTask. I have a difficulty when extracting a value from XML, then passing it to a parameter as a string. The cmdlet allows me to specify an exported XML file as the definition of the scheduled task. In principle, my command is "create a new scheduled task from this XML". The cmdlet provides explicit parameters for TaskName, TaskPath and User, but I would like to obtain these directly from the XML. I can successfully use the XML notation to obtain the URI from the XML. I can successfully split this into a $TaskName and a $TaskPath. I can also obtain the Principal Userid from the XML. But when I pass this to the cmdlet as $User I receive an error "No mappings between account names and security IDs was done". The strange thing is that the $TaskName contains spaces, but is accepted by the cmdlet. The $User may or may not have spaces, but is not accepted. Whereas if I simply create $User as a normal quoted string variable it is accepted. Relevant snippets:

[xml]$taskXml = Get-Content -Path $XmlPath
$taskUser = $($task.xml.Task.Principals.Principal.UserId)
[string]$User = $(taskUser | Out-String)
Register-ScheduledTask -Xml (Get-Content -Path $XmlPath -Raw) -User $User

If I simply specify the $User = "S-1-5-18", for example, the cmdlet works. It might be a simple problem of passing strings that need to be quoted. But $TaskName (derived from the XML) also has spaces, and that passes fine to the parameter -TaskName. What is going on?

AirAzure
  • 97
  • 1
  • 5

1 Answers1

0

Do not use Out-String, because it invariably adds a trailing newline to its output.

Type-constraining your $User variable as [string] implicitly performs stringification (albeit via .ToString(), not via PowerShell's for-display-formatting system, the way Out-String does for non-primitive .NET types).

Additionally, passing a value to Register-ScheduledTask's -User parameter also implicitly stringifies via .ToString(), given that it is [string]-typed:

Therefore, the following is presumably enough:

[xml] $taskXml = Get-Content -Raw $XmlPath
$taskUser = $taskXml.Task.Principals.Principal.UserId
Register-ScheduledTask -Xml (Get-Content -Path $XmlPath -Raw) -User $taskUser

Note that I've corrected what I presume is a typo: $task.xml. -> $taskXml.

As an aside:

  • For robustness [xml] (Get-Content ...) should be avoided, because Get-Content may misinterpret the character encoding of XML files. Use the [xml] type's .Load() method instead; e.g.: ($xmlDoc = [xml]::new()).Load((Convert-Path ./file.xml)) - see the bottom section of this answer for details.
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I have marked this as the correct answer because it answered a lot of puzzles for me. The Register-ScheduledTask cmdlet is full of puzzles. – AirAzure Nov 29 '22 at 07:27
  • Register-ScheduledTask: It takes a parameter of "Xml" but requires this as a string. It cannot read the xml to obtain the "TaskName" or "TaskPath" values. These must either be supplied, or obtained by parsing the xml as xml. My problem with the "User" parameter was a complete red herring, and in fact the parsing of the xml was valid. Type-constraining the variables was a big help in debugging. Thanks for the aside about getting/loading the xml. – AirAzure Nov 29 '22 at 07:38