I want to use PowerShell to create a scheduled task under the security context of a specific (administrator) user.
Wheter a local or domain account is used, "Register-ScheduledTask" alsways fail with error 0x8007025c and message "The variant structure provided contains invalid data." (Translated from French "La structure variante fournie contient des données non valides.").
Of course, there is no issue when the task principal is the SYSTEM service account.
The test program below shows this behavior. After displaying the current PowerShell version, it simply asks if it should fail or not. In the first case, the output is:
PS C:\Users\Admin> C:\Rustines\ShowRegisterScheduledTaskFailure.ps1
This is PowerShell 5.1.26100.8875
Show failure (Y/N): y
La structure variante fournie contient des données non valides.
HRESULT 0x8007025c,Register-ScheduledTask
PS C:\Users\Admin>
In the second case, the output is:
PS C:\Users\Admin> C:\Rustines\ShowRegisterScheduledTaskFailure.ps1
This is PowerShell 5.1.26100.8875
Show failure (Y/N):
Done!
PS C:\Users\Admin>
and the task is created. The result is the same whether "Admin" is a local or domain administrator.
The test program is included below (save as ShowRegisterScheduledTaskFailure.ps1).
I cannot find a single example of such a simple issue on the Internet ;-)
Regards,
Write-Host "This is PowerShell ", $($PSVersionTable.PSVersion -join ".")
# Fail/Nofail
$ShowFailure = $(Read-Host "Show failure (Y/N)").Trim().ToLower() -eq "y"
# Define parameters
$taskName = "TestLogon"
#Check for an existing instance of the Scheduled Task, if found, delete it
Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue | Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
# Dummy workload for successful
$scriptBlock = 'Add-Content -Path C:\TestLogon.txt -Value "$(Get-Date)" '
# Get current date/time and subtract 1 hour so that Task Scheduler will ignore this task
$userDateTime = (Get-Date).AddHours(-1)
# Create scheduled task
$taskActions = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -WindowStyle Hidden -Command `$($scriptBlock)` "
$trigger = New-ScheduledTaskTrigger -Once -At $userDateTime
$taskDescription = "Init System Update"
$taskSettings = New-ScheduledTaskSettingsSet -DontStopIfGoingOnBatteries
# Create Scheduled Task variables
if ($ShowFailure) {
# Prompt for username and password
$taskCredentials = Get-Credential -Message "Enter your username and password"
# Create a ScheduledTaskPrincipal using the username from the credential
$taskPrincipal = New-ScheduledTaskPrincipal `
-UserId $taskCredentials.UserName `
-LogonType Password `
-RunLevel Highest
# Do not uses -AsJob : a structure of type "ThrottlingJob" is created rather than
# the CimInstance required by New-ScheduledTask below.
# Contrary to documentation, this cmdlet does not have a "Password" parameter.
# See (Get-Command New-ScheduledTaskPrincipal).Parameters.Keys
} else {
$taskPrincipal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-LogonType ServiceAccount `
-RunLevel Highest
}
# If you want to use a security principal object created by New-ScheduledTaskPrincipal
# you MUST use the -InputObject approach.
$task = New-ScheduledTask `
-Description $taskDescription `
-Action $taskActions `
-Settings $taskSettings `
-Trigger $trigger `
-Principal $taskPrincipal
# Register the scheduled task with the stored credential
try {
if ($ShowFailure) {
$Result = Register-ScheduledTask -ErrorAction Stop `
-TaskName $taskName `
-InputObject $task `
-Password "$($taskCredentials.GetNetworkCredential().Password)"
} else {
$Result = Register-ScheduledTask -ErrorAction Stop `
-TaskName $taskName `
-InputObject $task
}
Write-Host "Done!" -ForegroundColor Green
}
catch {
Write-Host $Error[0].Exception.Message -ForegroundColor Red
Write-Host $Error[0].FullyQualifiedErrorId -ForegroundColor Red
}