Running a Scheduled Task after another

Within the Windows Task Scheduler it is possible to fire off processes based on a lot of different triggers, both time based, and windows event based. However it seemed quite hard to fire off one scheduled task after another had completed, despite there being an event log showing the task starting, running and completing:clip_image002[4]

The main reason for running one Scheduled Task after another was due to the change in user running the task, so they could not be chained as the same task.

The following example is much more simplified, but the underlying solution is the same.

I have created a very simple Ping Task which displays a message, and wanted to chain a Pong task to run directly after this has completed. Creating the tasks are quite simple, but now I want to set a trigger on Pong for when the Ping task completes. This proved a little more difficult, though “On Event” appeared to be the right way to go, as the Task Scheduler outputs events at all points in the operation of a Task.

The most interesting one to me was the “Task Completed” event you can see above. Looking at XML view within the details of this event it appeared that I knew all the EventData I needed to know to run the Pong task on:

clip_image004[4]

The trouble was with the Basic On an event trigger, you could only specify the Event ID which is 102 for all Task completed events on all Tasks, and not just my Ping Task:

clip_image006[4]

However it is possible to define a Custom Event, though the standard filter does not allow much control over the selection of the events:

clip_image008[4]

Using this as a starting point, and selecting the most that I could in this dialogue also started to populate the custom XML XPath, which would allow far more control.

clip_image010[4] clip_image012[4]

Now to start writing the XPath and refering to the XML from the TaskCompleted Event:

 <Event xmlns="https://schemas.microsoft.com/win/2004/08/events/event">
    <System>
       <Provider Name="Microsoft-Windows-TaskScheduler" Guid="{DE7B24EA-73C8-4A09-985D-5BDADCFA9017}" />
       <EventID>102</EventID>
       <Version>0</Version>
       <Level>4</Level>
       <Task>102</Task>
       <Opcode>2</Opcode>
       <Keywords>0x8000000000000001</Keywords>
       <TimeCreated SystemTime="2011-10-25T16:20:39.200166100Z" />
       <EventRecordID>109987</EventRecordID>
       <Correlation ActivityID="{13A3621A-839B-4FCD-83F3-B6677F1EC9F2}" />
       <Execution ProcessID="9372" ThreadID="8744" />
       <Channel>Microsoft-Windows-TaskScheduler/Operational</Channel>
    </System>
    <EventData Name="TaskSuccessEvent">
       <Data Name="TaskName">\Ping</Data>
       <Data Name="InstanceId">{13A3621A-839B-4FCD-83F3-B6677F1EC9F2}</Data>
    </EventData>
 </Event>

 

I could use an XPath to get the Data element with TaskName of \Ping:

 <QueryList>
    <Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational">
       <Select Path="Microsoft-Windows-TaskScheduler/Operational">*[EventData
 [@Name='TaskSuccessEvent'][Data[@Name='TaskName']='\Ping']]</Select>
    </Query>
 </QueryList>
  

clip_image014[4]

By adding this trigger, and firing the Ping Event, the Pong Task Fires immediately after the Ping is complete.

Breaking the XPath down further:

clip_image001

It is now a simple case of reusing this XPath replacing the Task Name, \Ping here, with the task to run after.