Automating scheduled tasks


Back in the day, I used to develop scheduled tasks by writing my own task scheduler and batch execution program.  I don’t think at the time I knew about the Task Scheduler service built in to Windows.  It support just about any scheduling algorithm I could throw at it, outside of building dependent or cascading tasks.

For build automation, I often want to create, stop and start these scheduled tasks.  Luckily, there’s a handy command-line tool to do so: schtasks.exe.  Not only can you administer tasks on your own machine, but other machines as well.  This is perfect for build and deployment automation, where I need to not only copy files, but execute SQL migration scripts, start/stop services, and power down/up scheduled tasks.

The command-line tool lets you do quite a few things:

  • Create a task
  • Delete a task
  • Run a task
  • End a task
  • Query a task for status/information
  • Modify a task

I typically don’t create the tasks, as that really only needs to happen once.  However, it would be fairly trivial for me to do so, and have all of the task setup driven through automation.

One thing I like to do is disable batch jobs before the deployment happens, then turn them all back on.  I don’t want to do this with all the tasks there, so I use NAnt to pull from a text file of the scheduled tasks I’m interested in.  However, I don’t want to disable running tasks, as I want to just let them finish and have the build stop:

<echo message="Disabling batch jobs..." />
<foreach item="Line" in="batchjobs.txt" property="taskName">
    <exec program="schtasks.exe" 
                commandline="/Query /TN ${taskName} /FO TABLE /NH" 
                output="task.txt" />
    <loadfile file="task.txt" property="batchjob.info" />
    <exec program="schtasks.exe" 
                commandline="/CHANGE /TN ${taskName} /DISABLE" 
                if="${string::contains(batchjob.info, 'Ready')}"/>
</foreach>

In this NAnt snippet, I loop through the batch jobs I care about.  I then call the “schtasks.exe”, querying the tasks status by name and outputting the result in the form of a table to a “task.txt” file.  Next, I load that file into a NAnt property.  Finally, I use the “/CHANGE” switch to disable the scheduled task, but ONLY IF its status is “Ready” and not “Running” or something else.

Next, I’ll run through the batch jobs file again, this time querying for any task that hasn’t been disabled.  If there are any, I’ll just fail the build.  I could sleep the build script, and poll until the task completes.

Once the build is done, I’ll enable all the configured scheduled tasks:

<echo message="Enabling batch jobs..." />
<foreach item="Line" in="batchjobs.txt" property="taskName">
    <exec program="schtasks.exe" commandline="/CHANGE /TN ${taskName} /ENABLE" />
</foreach>

Build automation can really cut down on those launch-night headaches and uncertainty.  Having a good command-line tool goes a long way to enabling easy build automation scripts.

Are daily stand-ups necessary?