Programmatically Triggering a Task Scheduler Job with Windows Events

Intro

Do you use Windows Task Scheduler to run scheduled batch jobs? It could be used for a great deal of things, e.g. sending out scheduled email reports or run a machine processes at a timed interval. I use it for running daily data imports, running optimization scripts on the database, sending scheduled emails and Push Notifications etc. In this quick tutorial, I will show you how to trigger a scheduled job programmatically. And just in case you are thinking, what’s the big deal? Use SCHTASKS, then you should already know that SCHTASKS fails at running tasks that require elevated permissions on the same local server instance.

Problem Statement

Why trigger a scheduled job programmatically?

Task Scheduler is used to schedule a batch job / script / program to run at a schedule. Software like Google Chrome, Apple iTunes, Graphics Drivers, Adobe Flash, etc. all schedule jobs in the Task Scheduler to check for updates. While these are fairly simple use cases and work perfectly well as long as you want to run the job on a schedule. The problem is when you want to trigger them manually. An example would be an Updater Script that runs periodically to check for software updates. Now what if you want to provide the end user a functionality to also trigger the update check manually by pressing a button on your app’s UI. Or what if you have a financial web app running on a server that uses Task Scheduler to send out monthly billing statements to customers. Now you would need to give your users a way to request for the last statement at the press of a button as well, else you risk having frustrated customers.

Why not use SCHTASKS?

Ok for those who don’t know, SCHTASKS is the command line interface to Task Scheduler and can be used to create, edit and run jobs manually. Since it can run jobs, the first thought would be to kick off the job using a simple command like SCHTASKS /Run /TN <task-name>

From within C# you could use Process.Start to achieve the needful. Try the same thing if your job needs elevated permissions or another user account to run and you will see SCHTASKS failing. This is critical because a scheduled job may need to access restricted resources like an encrypted folder or perform administrative system functions. So how do we get around that?

Solution

Scheduled jobs can be configured to have triggers. The primary trigger in 90% of the use cases is a scheduled time when the job would need to kick off. However there are a few more trigger options as you will see in this screenshot below

You will notice that your job can be triggered by a number of trigger mechanisms, schedule being the most popular use case. But we want a programmable trigger. “On an event” is perfect for our case because we can generate an event in the Event Log. Let’s get working and see how to make it happen.

Step 1. Create the “Event Source”

You can use the eventcreate.exe command or use a PowerShell command shown below

Command Line

eventcreate /ID 1 /L APPLICATION /T INFORMATION  /SO MYEVENTSOURCE /D "My first log"

PowerShell 2.0

New-EventLog -LogName Application -Source MYEVENTSOURCE

What the above does is create a distinct Event Source for us. This allows are job to “listen” for events coming from a specific event source. If we define our own event source specific to our application, we can then take custom actions based on the eventid.

Now, let us review where we are:

  • We know how to create Scheduled Jobs/Tasks with Event based Triggers
  • We know how to create a Custom event source for our application
  • We can define a set of unique event IDs specific to our application (it can be any random numbers) that our code knows how to handle
  • What remains to be seen is how can we log an event into the Windows Event Log programmatically

Step 2. Create a Scheduled Task with an Event Trigger

The below screenshot explains it all. Scheduled Tasks are easy to create. Usually most tasks have a time schedule, for example, daily at 12 am. All we are doing different is adding a trigger whose trigger is an event, as shown in the screenshot below.

Now define the trigger to listen to an event as shown below

Notice how we picked our custom MYEVENTSOURCE in the Source select box. The number in the event id, 24311, is a custom event id and can be any number you want. You may have different tasks listen for event ids. For example, I may configure a job to run for Client A when the event ID is 24311 or a Client B when the event ID is 24312. It purely is our choice.

Step 3. Log an Event from code

You can do this with almost any programming language, but in my example I will use C#.


var source = "MYEVENTSOURCE";

try
{
    EventLog.WriteEntry(source, "Run Import", EventLogEntryType.Information, 24311);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

Yep, now watch your Scheduled Task kick off automatically when this C# snippet logs an event.

Conclusion

Well, now you know this neat trick that can start your job programmatically on-demand. I have found this extremely useful in scenarios where I was earlier planning to use a Windows Service, but I could eventually void writing and configuring services by simply using the powerful Task Scheduler which is a part of your Windows OS and configuring programmatic event triggers. Hope this helps you in some way.

Fax services on Vista home premium

All the Windows Vista Home Premium users by now must have figured out that they don’t have the basic Windows Fax and Scan services. Too bad Microsoft decided to remove something that basic from an already crappy operating system. The only solution is to look for an alternate and I seem to have found a good alternate – Classic Phone Tools by Avanquest Software

You can get the full version for free if you follow the right links on the page. So far it seems to work great for me! Let me know if anyone of you knows other better Windows Fax software.