Powershell v4. Create remote task scheduler task set to expire and delete

12,623

Solution 1

With some help from Craig Duff, here is how you can create a task that is deleted after being run without the compatibility flag and using the PS4.0 cmdlets:

$run = (Get-Date).AddMinutes(2) # Two minutes from now
Register-ScheduledTask -TaskName "MyTask"  -User "Domain\User" -InputObject (
  (
    New-ScheduledTask -Action (
      New-ScheduledTaskAction -Execute "C:\path\to\your.exe" -Argument (
        "many" + 
        "arguments " +
        """with quotes"" "
      )
    ) -Trigger (
      New-ScheduledTaskTrigger -Once -At ($run.TimeOfDay.ToString("hh\:mm")) # As a "TimeOfDay" to get 24Hr format
    ) -Settings (
      New-ScheduledTaskSettingsSet  -DeleteExpiredTaskAfter 00:00:01 # Delete one second after trigger expires
    ) 
  ) | %{ $_.Triggers[0].EndBoundary = $run.AddMinutes(60).ToString('s') ; $_ } # Run through a pipe to set the end boundary of the trigger
)

The thing is that the trigger must have an EndBoundary defined so that the task can be deleted. The New-ScheduledTaskTrigger cmdlet doesn't have a parameter to define it. The trick is then to create the task and register it in two different steps, with a step in between to define the End Boundary of the trigger. Obviously if your task has more than one trigger, you would need to set the End Boundary for each.

This specific example creates a task that will run c:\path\to\your.exe once called MyTask two minutes into the future, running with credentials Domain\User. The trigger will expire an hour after the execution start (just so someone could verify if it was run from the scheduled tasks window, instead of browsing through the windows logs), and the task will be deleted one second after that.

Solution 2

This error is caused by a bug introduced in the Task Scheduler back in Vista. Read more here "The task XML is missing a required element or attribute" error when you use the /z switch together with the Schtasks command in Windows Vista

The work around is to create a task compatible with pre-Windows Vista platforms, if you want to use the -DeleteExpiredTaskAfter parameter.

This is

-Compatibility V1

Or in your code

$settings = New-ScheduledTaskSettingsSet -Compatibility V1 -DeleteExpiredTaskAfter 00:00:01 -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 01:00:00 -RestartCount 3

There are other things to look out for when setting a scheduled task to expire.

Valid values.

There is only a limited number of values that are valid a parameter "-DeleteExpiredTaskAfter". These are Imediately (PT0S), 30 days (P30D), 90 days (P90D), 180 days (P180D) and 365 days (P365D).

Other Prerequisites

Before a task can be set to expire there has to be a trigger with an expiration time (EndBoundary) set.

This is where I'm stuck at the moment, because new PS4.0 cmdlets don't seem to cater for this.

In the meantime here is an "old school" way of setting up a scheduled task directly via Scheduler Service COM interface.

$server = "...."
$domain = $server
$user = "...."
$password = "...."

$ExecuteTime = (Get-Date).AddDays(1)
$ExpireTime = $ExecuteTime.AddMinutes(1)

$taskname = "Reboot $server"
$taskpath  = "PendingReboots"
$taskdesc = "Server Reboot"

$ShedService = new-object -comobject "Schedule.Service"
$ShedService.Connect($server, $user, $domain, $password)

$Task = $ShedService.NewTask(0)
$Task.RegistrationInfo.Description = "$taskdesc"
$Task.Settings.Enabled = $true
$Task.Settings.AllowDemandStart = $true
$Task.Settings.DeleteExpiredTaskAfter = "PT0S"
$Task.Settings.ExecutionTimeLimit = "PT1H"
$Task.Settings.StopIfGoingOnBatteries = $false
$Task.Settings.RestartCount = 3

$trigger = $task.triggers.Create(1) # Creates a "One time" trigger
#    TASK_TRIGGER_EVENT     0
#    TASK_TRIGGER_TIME      1
#    TASK_TRIGGER_DAILY     2
#    TASK_TRIGGER_WEEKLY    3
#    TASK_TRIGGER_MONTHLY   4
#    TASK_TRIGGER_MONTHLYDOW    5
#    TASK_TRIGGER_IDLE      6
#    TASK_TRIGGER_REGISTRATION  7
#    TASK_TRIGGER_BOOT      8
#    TASK_TRIGGER_LOGON     9
#    TASK_TRIGGER_SESSION_STATE_CHANGE  11

$trigger.StartBoundary = $ExecuteTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
$trigger.EndBoundary = $ExpireTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
$trigger.Enabled = $true

$Action = $Task.Actions.Create(0)
$action.Path = "shutdown.exe"
$action.Arguments = " -r -f -t 0"

Try {$taskFolder = $ShedService.GetFolder("\$taskpath")}
catch {$taskFolder = $ShedService.GetFolder("\").CreateFolder("$taskpath")}

$result = $taskFolder.RegisterTaskDefinition("$TaskName",$Task,6,"System",$null,5)
Share:
12,623
Doms
Author by

Doms

Updated on June 04, 2022

Comments

  • Doms
    Doms almost 2 years

    I am trying to create a task that essentially reboots the server but the task is put there by a remote server running a check to see if a reboot is needed. I am stuck trying to add an expiration so it deletes itself but can't find where to put that setting or what it is. It has to do with an end boundry or something and this setting -DeleteExpiredTaskAfter but don't know what value to put in.

    $dc = "server2reboot"
    $taskname = "Reboot $DC"
    $taskpath  = "PendingReboots"
    $CimSession = New-CimSession -ComputerName $dc -Credential $credentials -Authentication Negotiate
    
    Function Create-AndRegisterRebootTask{
     Param ($taskname, $taskpath)
     $action = New-ScheduledTaskAction -Execute '#shutdown.exe -r -f -t 0"'
     $trigger =  New-ScheduledTaskTrigger -once -At ("$nextsundaydate 3:00") -RandomDelay 03:00:00 
     Register-ScheduledTask -CimSession $cimsession -RunLevel Highest  -Action $action -Trigger $trigger -TaskName $taskname -Description "Server Reboot" -TaskPath $taskpath -Force
     }
    
    
    
    Function Create-NewRebootTaskSettings{
     Param ($taskname, $taskpath)
     $settings = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter "PT0S" -compatability "win8" -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit "PT1H" -RestartCount 3
     Set-ScheduledTask -CimSession $cimsession -TaskName $taskname -Settings $settings -TaskPath $taskpath
     }
    
    Create-AndRegisterRebootTask -taskname $taskname -taskpath $taskpath 
    Create-NewRebootTaskSettings -taskname $taskname -taskpath $taskpath 
    
    Set-ScheduledTask : The task XML is missing a required element or attribute.
    (48,4):EndBoundary:
    At line:5 char:2
    +  Set-ScheduledTask -CimSession $cimsession -TaskName $taskname -Settings $settin ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (PS_ScheduledTask:Root/Microsoft/...S_ScheduledTask) [Set-ScheduledTask], CimException
        + FullyQualifiedErrorId : HRESULT 0x80041319,Set-ScheduledTask
    
  • Doms
    Doms about 9 years
    That "PT0S" is not working either. cannot convert value to system.timespan
  • Jan Chrbolka
    Jan Chrbolka about 9 years
    Use a numerical timevalue instead 00:00:01 = 1s
  • Doms
    Doms about 9 years
    it did not like that 00:00:01 format either with the V1 change. I put in 60 and win8 and I get no error but it also doesn't do anything to the expire check box.
  • Jan Chrbolka
    Jan Chrbolka about 9 years
    I have edited the answer. Looks like setting an "EndBounary" expiration date for a Trigger is a prerequisite. This is proving to be a challenge.
  • Doms
    Doms about 9 years
    Found this tomsitpro.com/articles/run-scripts-across-reboots,2-874.html and this stackoverflow.com/questions/1669026/… don't know how to incorporate it or if it will work.
  • Jan Chrbolka
    Jan Chrbolka about 9 years
    Thanks for the references. I still can’t get the PS 4 cmdlets to work. They will work locally, but not on a remote server. I have added code to the answer using the “old” way, via COM interface. This works.