Getting alerted when a Windows scheduled task fails

I am looking for a way to get alerted if any of the scheduled tasks on a group of Windows 2003 servers fail (exit with a status code that is not 0). Scripts, commercial applications, and plug-ins to monitoring tools (like Nagios) are all open for consideration.

ActiveXperts Network Monitor comes up in most search results, but the scheduled task monitoring feature is a small part of a large commercial network monitoring package.

Below is a batch file script that will dump out the scheduled task results to a csv file that can be imported into SQL Server using SSIS.

rem MC: dump the scheduled task results into the specified outfile
@echo off

set outfile=c:\temp\scheduled_tasks.csv

rem MC: the for loop skips over the first blank that schtasks adds to the output
for /f "TOKENS=*" %%A in ('schtasks /query /fo csv /v') do ( echo %%A >> %outfile% )

The downside of this approach is that importing the csv file into a database table, running a query looking for status codes that are not 0, and sending out E-mails with alerts if anything was found seems like a cumbersome setup. I would rather use an existing solution than create a complex custom system from scratch.


Solution 1:

I do this as part of the scheduled job. All the scheduled jobs I run are scripts. Even if it's a graphical app I launch it from a .bat file. All the scripts include error checking, and they use osql to append a row to a "job monitoring" table. Then one query on the table tells me which jobs succeeded, failed or (courtesy of a left join) didn't report any status. I run this query as a scheduled job on my own workstation and it mails me a report.

JR

Solution 2:

Parse the output of the "schtasks" yourself using ADODB.

Here's a little VBScript program that will parse the output with pre-made IF/THEN blocks for "Last Result" not equal to zero, and "Status" as "Could Not Start". You can write in as many more conditions as you like and substitute code in to act upon the failure conditions however you want.

Option Explicit

' ADO Constants
Const adCmdText = 1
Const adLockOptimistic = 3
Const adOpenStatic = 3

' Path to text file and filename
Const FILEPATH = "C:\WINDOWS\TEMP"  ' Don't append "\"
Const FILENAME = "tasks.csv"

Dim x, objShell, objConn, objRS, dictFields, Field

' Write output of schtasks to file
Set objShell = CreateObject("WScript.Shell")
objShell.Run "%COMSPEC% /c schtasks /query /fo csv /v > """ & FILEPATH & "\" & FILENAME & """", 1, True

' Connect recordset to CSV file
Set objConn = CreateObject("ADODB.Connection")
Set objRS = CreateObject("ADODB.Recordset")

objConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FILEPATH & ";Extended Properties=""text;HDR=YES;FMT=CSVDelimited"""
objRS.Open "SELECT * FROM " & FILENAME, objConn, adOpenStatic, adLockOptimistic, adCmdText

' Load header into dictionary - Prefer to do this in case format changes in future version of Windows
Set dictFields = CreateObject("Scripting.Dictionary")

x = 0
For Each Field in objRS.Fields
    dictFields.Add Ltrim(Rtrim(Field)), x
    x = x + 1
Next ' Field
objRS.MoveNext

Do Until objRS.EOF

    ' Check last status for something other than 0
    If objRS.Fields.Item(dictFields("Last Result")) <> 0 Then 
        WScript.Echo "Scheduled Task " & objRS.Fields.Item(dictFields("TaskName")) & " returned status of " & objRS.Fields.Item(dictFields("Last Result"))
    End If

    ' Check "Status" for "Could Not Start"
    If NOT IsNull(objRS.Fields.Item(dictFields("Status"))) Then
        If UCase(objRS.Fields.Item(dictFields("Status"))) = "COULD NOT START" Then  
            WScript.Echo "Scheduled Task " & objRS.Fields.Item(dictFields("TaskName")) & " could not start"
        End If
    End If

    objRS.MoveNext
Loop