There are times that an app needs to perform a function at a specific time and date: once a week, once a month, every day, twice a month, and so on. There are apps specifically designed for this purpose. The app gets set up through the Windows Task Scheduler and executes on the set time(s) and date(s). Today, we will create an app that can set up task schedules automatically as well as investigate the current schedules of apps.
Windows Task Scheduler
According to MSDN, The Task Scheduler enables you to automatically perform routine tasks on a chosen computer. The Task Scheduler does this by monitoring whatever criteria you choose to initiate the tasks and then executing the tasks when the criteria is met.
The following tasks can be scheduled to execute:
- When a specific system event occurs
- At a specific time
- At a specific time on a daily schedule
- At a specific time on a weekly schedule
- At a specific time on a monthly schedule
- At a specific time on a monthly day-of-week schedule
- When the computer enters an idle state
- When the task is registered
- When the system is booted
- When a user logs on
Task Scheduler Wrapper
There exists a wrapper for the Windows Task Scheduler. This wrapper can be found on CodePlex. CodePlex is Microsoft’s free open source project hosting site. Here, you can create projects to share with others, collaborate with others on their projects, and even download open source software.
The Task Scheduler Managed Wrapper provides a wrapper for the Windows Task Scheduler. A wrapper “wraps” or “encapsulates” the functionality of another class or component. Wrappers provide a level of abstraction from the implementation of the underlying class or component.
We will make use of this wrapper in our project. You can download it directly from CodePlex. You also can read up on its documentation here.
Our Project
Start Visual Studio and create a new Windows Forms Project. Once the form is displayed, design your form to resemble Figure 1.
Figure 1: Our Design
After you have downloaded the Wrapper (in the link given earlier), you need to set a reference to it in your program. You do this by selecting Project, Add Reference. Select the Browse tab and browse to the DLL file’s location, as shown in Figure 2.
Figure 2: Reference
The Reference to the Task Scheduler Wrapper has now been added to your app. You can make use of its full power.
Code
Import the library that you have referenced earlier:
Imports Microsoft.Win32.TaskScheduler
Add the next code behind the button labeled ‘Create A Task’:
Using tService As New TaskService() Dim tDefinition As TaskDefinition = tService.NewTask tDefinition.RegistrationInfo.Description = _ "Example Task" Dim tTrigger As New WeeklyTrigger() tTrigger.StartBoundary = DateTime.Today.AddDays(2) tTrigger.DaysOfWeek = DaysOfTheWeek.Saturday Or _ DaysOfTheWeek.Sunday tTrigger.WeeksInterval = 5 tTrigger.Repetition.Duration = TimeSpan.FromHours(4) tTrigger.Repetition.Interval = TimeSpan.FromMinutes(10) tDefinition.Triggers.Add(tTrigger) tDefinition.Actions.Add(New ExecAction("notepad.exe", _ "c:\Example Task.log")) tService.RootFolder.RegisterTaskDefinition("Example Task", _ tDefinition) End Using
A TaskDefinition object gets created; it contains the Task’s information, such as its name. A Trigger is set up. I will speak about Triggers a bit later. After the WeeklyTrigger object has been set up, an ExecAction gets added to the TaskDefinition object. ExecAction is responsible for executing an application, such as Notepad in the preceding example. The last task is to register the Task inside Windows via the help of the TaskService’s RegisterTaskDefiition method.
Creating Different Triggers
You can create the various types of Triggers with code similar to the following:
'Boot Trigger' Dim tBoot As New BootTrigger() tBoot.Delay = TimeSpan.FromMinutes(3) 'DailyTrigger' Dim tDaily As New DailyTrigger() tDaily.StartBoundary = DateTime.Today _ + TimeSpan.FromHours(10) tDaily.DaysInterval = 4 tDaily.RandomDelay = TimeSpan.FromHours(2) 'IdleTrigger' Dim tIdle As New IdleTrigger() tIdle.ExecutionTimeLimit = TimeSpan.FromMinutes(30) 'LogonTrigger' Dim tLogon As New LogonTrigger() tLogon.Delay = TimeSpan.FromMinutes(15) tLogon.UserId = "HTG" 'MonthlyTrigger' Dim tMonthly As New MonthlyTrigger() tMonthly.StartBoundary = DateTime.Today.AddDays(1) tMonthly.DaysOfMonth = New Integer() {27, 24} tMonthly.MonthsOfYear = MonthsOfTheYear.July Or _ MonthsOfTheYear.August tMonthly.RunOnLastDayOfMonth = False 'MonthlyDOWTrigger' Dim tMonthlyDOW As New MonthlyDOWTrigger() tMonthlyDOW.StartBoundary = DateTime.Today _ + TimeSpan.FromHours(1) tMonthlyDOW.DaysOfWeek = DaysOfTheWeek.Saturday tMonthlyDOW.MonthsOfYear = MonthsOfTheYear.January Or _ MonthsOfTheYear.December tMonthlyDOW.WeeksOfMonth = WhichWeek.FirstWeek Or _ WhichWeek.LastWeek 'TimeTrigger' Dim tTime As New TimeTrigger() tTime.StartBoundary = New DateTime(DateTime.Today.Year, _ 12, 31, 23, 59, 0) 'EventTrigger' Dim eTrigger As New EventTrigger() eTrigger.Subscription = "<QueryList><Query Id='1'> _ <Select Path='System'> *[System/Level=2]</Select></Query> _ </QueryList>" eTrigger.ValueQueries.Add("Name", "Value") 'RegistrationTrigger' Dim rTrigger As New RegistrationTrigger() rTrigger.Delay = TimeSpan.FromMinutes(5) 'SessionStateChangeTrigger' New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.ConsoleConnect, _ Key .UserId = "joe" _ } New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.ConsoleDisconnect _ } New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.RemoteConnect _ } New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.RemoteDisconnect _ } New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.SessionLock, _ Key .UserId = "joe" _ } New SessionStateChangeTrigger() With { _ Key .StateChange = TaskSessionStateChangeType.SessionUnlock _ }
More information about Triggers can be found here.
Add the following code to identify a Task and then do something productive with it. For example, you can Delete it:
Private Sub GetAndDeleteTask(strTaskName As String) Using tService As New TaskService() Dim tTask As Task = tService.GetTask(strTaskName) If tTask Is Nothing Then Return End If tTask.Definition.Triggers(0).StartBoundary = _ DateTime.Today + TimeSpan.FromDays(2) tTask.RegisterChanges() tService.RootFolder.DeleteTask(strTaskName) End Using End Sub Private Sub Button3_Click(sender As Object, e As EventArgs) _ Handles Button3.Click GetAndDeleteTask("NameOfTask") End Sub
Add the following code to display a list of all tasks that are scheduled to run with the Windows Task Scheduler:
Private Sub ShowAllTasks() Using tService As New TaskService() ShowFolderTasks(tService.RootFolder) End Using End Sub Private Sub ShowFolderTasks(tFolder As TaskFolder) For Each tTask As Task In tFolder.Tasks DisplayDetails(tTask) Next For Each tSubFolder As TaskFolder In tFolder.SubFolders ShowFolderTasks(tSubFolder) Next End Sub Private Sub DisplayDetails(tTask As Task) ListBox1.Items.Add(tTask.Name + "" + tTask.Path + "" _ + tTask.LastRunTime) End Sub Private Sub Button4_Click(sender As Object, e As EventArgs) _ Handles Button4.Click ShowAllTasks() End Sub
This loops through all the Root tasks and their respective SubRoot Tasks and displays the particular tasks’ details.
Figure 3: All Tasks
Conclusion
Having the ability to manipulate the Windows Task Scheduler from a separate program is quite awesome. It comes in very handy, especially when the task you need to schedule is on a separate server.