Monitoring Windows Task Scheduler jobs

Updated November 3, 2026

Task Scheduler is cron for Windows: it runs backups, report exports and maintenance scripts on servers and office machines. It also keeps quiet when something goes wrong. A failed task shows a code like 0x1 in a column nobody looks at, and the built-in “Send an e-mail” action has been deprecated since Windows 8 and Server 2012. Here is how to read the results, avoid the usual traps and get an alert when a task fails or doesn’t run.

What “Last Run Result” means

CodeMeaning
0x0The program exited with code 0
0x1, 0x2…The program’s own exit code: 1, 2 and so on. For PowerShell, 0x1 often means the script threw an error or couldn’t be loaded
0x41301The task is running right now
0x41303The task has never run
0x41306The task was stopped, by a user or by the time limit
0x800710E0The task was refused, usually because of the account or its rights

The History tab is empty by default. Turn it on with “Enable All Tasks History” in the Actions pane of Task Scheduler.

The usual traps

A wrapper that reports to Heartcron

Instead of starting the job directly, start this script. It reports the start, runs the job, and sends the exit code with the end of the output. It works in Windows PowerShell 5.1 and PowerShell 7:

# C:\Jobs\run-backup.ps1
$url = "https://ping.heartcron.com/<uuid>"

try { Invoke-RestMethod "$url/start" -TimeoutSec 10 | Out-Null } catch {}

$out = & "C:\Jobs\backup.exe" --full *>&1 | Out-String
$code = $LASTEXITCODE
if ($null -eq $code) { $code = 0 }

if ($out.Length -gt 100000) { $out = $out.Substring($out.Length - 100000) }
try { Invoke-RestMethod "$url/$code" -Method Post -Body $out -TimeoutSec 10 | Out-Null } catch {}

exit $code

If the job is itself a PowerShell script, call it as & powershell.exe -NoProfile -File C:\Jobs\backup.ps1 so that $LASTEXITCODE is set, and end that script with exit.

Create the task

From an elevated PowerShell, run the wrapper every night at 3:00 as SYSTEM:

$action  = New-ScheduledTaskAction -Execute "powershell.exe" `
           -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Jobs\run-backup.ps1" `
           -WorkingDirectory "C:\Jobs"
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
Register-ScheduledTask -TaskName "Nightly backup" -Action $action -Trigger $trigger `
           -User "SYSTEM" -RunLevel Highest

Or the same with schtasks:

schtasks /Create /TN "Nightly backup" /SC DAILY /ST 03:00 /RU SYSTEM /RL HIGHEST ^
  /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Jobs\run-backup.ps1"

In Heartcron, create a check with the cron expression 0 3 * * * in the machine’s time zone, and a grace period longer than the backup usually takes. Weekly or monthly triggers translate to cron too; the cron expression explainer shows what an expression means.

Test it

Start-ScheduledTask -TaskName "Nightly backup"
Get-ScheduledTaskInfo -TaskName "Nightly backup"   # LastTaskResult should be 0

The check in Heartcron should show the start and the success with the duration. Then make the job fail once to see the alert and the output.

Without a wrapper

The open-source heartcron CLI has a Windows build and does the same as the script above: heartcron.exe run nightly-backup -- C:\Jobs\backup.exe --full. Put that line in the task’s action.

More guides