Monitor a Windows Task Scheduler job
Windows Task Scheduler records a task’s last result, but only someone who opens it on the server sees it. When the script starts failing, the service account’s password expires, or the task is disabled during maintenance, nobody notices. A heartbeat check does: the script reports to Pingstack after it succeeds, and Pingstack alerts you when that report doesn’t arrive on time.
1. Create a heartbeat check that matches the schedule
Section titled “1. Create a heartbeat check that matches the schedule”Task Scheduler triggers aren’t cron, so translate the trigger:
| Task Scheduler trigger | Pingstack schedule |
|---|---|
| Daily at 2:00 AM | Cron 0 2 * * * |
| Weekly on Monday at 6:30 AM | Cron 30 6 * * 1 |
| Monthly on day 1 at 3:00 AM | Cron 0 3 1 * * |
| Repeat every 15 minutes | Interval of 15 minutes |
Create a heartbeat check with the matching schedule. Task Scheduler uses the server’s local time, so choose the server’s timezone in Pingstack. See schedules and timezones.
Set a grace period longer than the task’s usual runtime. Attach a notification group.
2. Store the ping URL where only the task can read it
Section titled “2. Store the ping URL where only the task can read it”Copy the location’s ping URL from the check in Pingstack. In an elevated PowerShell, save it to a file and restrict it to administrators and the account the task runs as:
$dir = 'C:\ProgramData\Pingstack'New-Item -ItemType Directory -Force -Path $dir | Out-NullRead-Host 'Ping URL' | Set-Content -Path "$dir\nightly-export.url" -NoNewlineicacls $dir /inheritance:r /grant:r 'Administrators:F' 'SYSTEM:F' 'DOMAIN\svc-export:R'Replace DOMAIN\svc-export with the task’s account.
3. Report success from the script
Section titled “3. Report success from the script”$ErrorActionPreference = 'Stop'
& 'C:\Jobs\export.exe' --target D:\exportsif ($LASTEXITCODE -ne 0) { throw "export.exe exited with $LASTEXITCODE" }
$url = (Get-Content -Raw 'C:\ProgramData\Pingstack\nightly-export.url').Trim()Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10 | Out-Null$ErrorActionPreference = 'Stop' turns PowerShell errors into failures, and
the $LASTEXITCODE check does the same for programs like export.exe, which
PowerShell doesn’t stop on by itself. Either way the script stops before the
report, and Pingstack alerts you when the deadline passes.
Register the task:
$action = New-ScheduledTaskAction -Execute 'powershell.exe' ` -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\Jobs\nightly-export.ps1'$trigger = New-ScheduledTaskTrigger -Daily -At 2am$cred = Get-Credential 'DOMAIN\svc-export'Register-ScheduledTask -TaskName 'Nightly export' -Action $action -Trigger $trigger ` -User $cred.UserName -Password $cred.GetNetworkCredential().PasswordRunning as a dedicated account with Run whether user is logged on or not keeps the task independent of who’s signed in.
4. Confirm the first report
Section titled “4. Confirm the first report”Start the task by hand:
Start-ScheduledTask -TaskName 'Nightly export'Get-ScheduledTaskInfo -TaskName 'Nightly export'When it finishes, open the check in Pingstack and confirm the location received a heartbeat and shows a next deadline.
Optional: report a number
Section titled “Optional: report a number”Append a count the job produces as a numeric value, then set warning and critical thresholds on the check:
$rows = (Get-ChildItem D:\exports -Filter *.csv).CountInvoke-WebRequest -Uri "$($url)?value=$rows" -UseBasicParsing -TimeoutSec 10 | Out-NullWhy a healthy task might still alert
Section titled “Why a healthy task might still alert”- Expired password. A task that stores the account’s password stops starting when the password changes. Update it in the task’s properties, or use a group managed service account.
- Server asleep or rebooting. Turn on Run task as soon as possible after a scheduled start is missed if late runs are acceptable; the late run reports after Pingstack has already alerted.
- Time limit. Task Scheduler stops tasks that run longer than the Stop the task if it runs longer than setting.
- Timezone or daylight saving. Local-time triggers shift with daylight saving. Match the check’s timezone to the server’s.
If alerts still don’t match what you expect, see troubleshooting monitoring.