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?
CodePudding user response:
Do not use Out-String
, because it invariably adds a trailing newline to its output.
- This problematic behavior is the subject of GitHub issue #14444
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, becauseGet-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.