Windows Task Scheduler monitoring
Task Scheduler keeps each task's last run time and last run result but never alerts on them, so monitor it with a small PowerShell watcher that pings an external monitor every 10 seconds while the last run is recent and clean.
Task Scheduler runs the job and keeps the receipt. Last Run Time and Last Run Result sit in two columns of the console, and that is all you get. The Send an e-mail action has been deprecated since Windows 8 and Server 2012, task history is off until someone clicks Enable All Tasks History, and nobody opens the console on a server that has worked for two years. That is how a backup task returns 0x1 for a month.
Task Scheduler last run result
Get-ScheduledTaskInfo returns what the console shows: LastRunTime, LastTaskResult, NextRunTime and NumberOfMissedRuns. LastTaskResult is the exit code of the action, so 0 is success and 1 is the generic failure most scripts return. A few values are states, not errors: 267009, or 0x41301, means the task is running right now, and 267011, or 0x41303, means it has never run. A check that treats every non-zero value as failure pages you every time the backup is mid-run.
Windows Task Scheduler monitoring with a heartbeat
Logdash push monitors are on Pro, $15 a month, and Pro checks each one every 15 seconds: no ping in that window, the monitor goes down and the alert goes out. A nightly task cannot ping that often, so a second task pings for it. The watcher below starts at boot, reads the task every 10 seconds, and posts to Logdash only while the last run started within 25 hours and either ended clean or is still going.
$task = 'Nightly Backup'
$maxAge = New-TimeSpan -Hours 25
$ping = 'https://api.logdash.io/ping/68b4c1f0e3a2d5c7b9f01234'
[Net.ServicePointManager]::SecurityProtocol = 'Tls12'
while ($true) {
$info = Get-ScheduledTaskInfo -TaskName $task
$fresh = ((Get-Date) - $info.LastRunTime) -lt $maxAge
# 0 = last run succeeded, 267009 = running right now
if ($fresh -and $info.LastTaskResult -in 0, 267009) {
try { Invoke-RestMethod -Method Post -Uri $ping -TimeoutSec 5 | Out-Null } catch {}
}
Start-Sleep -Seconds 10
}$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
-Argument '-NoProfile -ExecutionPolicy Bypass -File C:\ops\watch-task.ps1'
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero)
Register-ScheduledTask -TaskName 'Logdash watch' -Action $action `
-Trigger $trigger -Settings $settings -User 'SYSTEM' -RunLevel Highest
Start-ScheduledTask -TaskName 'Logdash watch'- The zero time limit matters. The default is 3 days, so without it Task Scheduler kills the watcher on day three and you get an alert for nothing.
- Tasks inside a folder need -TaskPath next to -TaskName, for example -TaskPath '\Backups\'.
- The TLS line is for Windows PowerShell 5.1 on older servers, which can still default to protocols the API refuses.
- A reboot stops the watcher, so patch night reads as a short outage with a down and an up message.
- Create a push monitor Add a service in Logdash on Pro, set the monitor to push and copy the monitor id from the ping URL. Name it after the task, since the alert shows the name.
- Install the watcher Save the script with your task name, window and monitor id, then run the registration block as administrator. If the last run was clean, the monitor goes green within 15 seconds.
- Break it on purpose Run Stop-ScheduledTask -TaskName 'Logdash watch'. Within 30 seconds a Telegram message lands saying the monitor is down, status code 0, did not receive call for this time range. Start it again and the up message follows.
Logdash vs Cronitor for Windows tasks
| Feature | Logdash | Cronitor |
|---|---|---|
| Setup | One watcher script and monitor per task | cronitor sync scans Task Scheduler and wraps the tasks you pick |
| What it alerts on | Last run stale or not clean | Late start, failure and long runtime, separately |
| Your task definition | Untouched, the watcher only reads it | Action rewritten to run through cronitor.exe |
| Server down | Alert within 30 seconds | Alert at the next missed run |
| Alert channels | Telegram and webhook | Email, Slack and more |
| Free plan | None for push monitors, Pro is $15 a month | 5 monitors free |
When Cronitor is the better pick
- You have more than a few tasks. cronitor sync finds them all and wraps the ones you choose in one pass.
- You want did not start, failed and ran too long as three different alerts, not one freshness window.
- Your servers reboot for patches every month and a short down and up message each time would be noise.
- Alerts must land in email or Slack, and 5 monitors on a free plan covers you.