Windows Scheduled Tasks Cheat Sheet

schtasks and the PowerShell scheduled task cmdlets: creating and querying tasks, the last result codes, and why a script that works by hand fails under the scheduler.

Start here

Did it run, and what came back
Get-ScheduledTaskInfo
Run it now, without waiting
schtasks /run /tn "Name"
Everything on this machine
schtasks /query /fo LIST /v
Why did it fail
TaskScheduler/Operational log
Move a task to another server
/query /xml then /create /xml
Works by hand, fails scheduled
Start in, account, or profile
Two different results to read. The task’s own last result says whether the scheduler could start and finish the job. The program’s exit code is what the job itself returned. A task can report success while the script inside it failed, which is why logging inside the script still matters.

Query and control

TaskCommand
All tasks, readableschtasks /query /fo LIST /v
One task in detailschtasks /query /tn "Nightly Backup" /fo LIST /v
Machine readableschtasks /query /fo CSV /nh
Export a task definitionschtasks /query /tn "Nightly Backup" /xml > backup.xml
Run nowschtasks /run /tn "Nightly Backup"
Stop a running taskschtasks /end /tn "Nightly Backup"
Disable without deletingschtasks /change /tn "Nightly Backup" /disable
Re-enableschtasks /change /tn "Nightly Backup" /enable
Deleteschtasks /delete /tn "Nightly Backup" /f
Against another machineschtasks /query /s SRV01 /u DOM\admin /p *

Creating a task

SwitchMeaning
/tnTask name, and its folder path if you want one
/trWhat to run, fully qualified
/scSchedule type, see the table below
/moModifier, the “every n” part
/stStart time, 24-hour HH:MM
/dDay: MON to SUN, or 1 to 31 for monthly
/ruAccount to run as. SYSTEM needs no password.
/rpPassword for that account
/rlHIGHEST or LIMITED. Default is LIMITED.
/fOverwrite an existing task of the same name
/iIdle minutes, required with ONIDLE
/xmlCreate from an exported definition
/sc valueWhen it runs
MINUTE, HOURLYEvery n minutes or hours, with /mo
DAILY, WEEKLY, MONTHLYEvery n days, weeks or months
ONCEA single run at a date and time
ONSTARTAt every system start
ONLOGONWhen a user logs on
ONIDLEAfter n idle minutes
ONEVENTOn a matching event, with an XPath query

Five that cover most real cases:

REM Nightly PowerShell job as a service account, elevated
schtasks /create /tn "Nightly Report" /tr "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\scripts\report.ps1" /sc daily /st 02:00 /ru "DOM\svc-report" /rp * /rl HIGHEST /f

REM Every 15 minutes as SYSTEM
schtasks /create /tn "Health Check" /tr "C:\scripts\check.cmd" /sc minute /mo 15 /ru SYSTEM /f

REM At every system start
schtasks /create /tn "Startup Fix" /tr "C:\scripts\fix.cmd" /sc onstart /ru SYSTEM /rl HIGHEST /f

REM Weekly, Monday morning
schtasks /create /tn "Weekly Purge" /tr "C:\scripts\purge.cmd" /sc weekly /d MON /st 06:00 /ru SYSTEM /f

REM Import a task exported from another server
schtasks /create /tn "Nightly Report" /xml backup.xml /ru "DOM\svc-report" /rp *
Always call the interpreter, never the script. /tr "C:\scripts\job.ps1" hands the file to whatever is associated with .ps1, which on a server is usually Notepad. Write powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\scripts\job.ps1 and the task does what you meant.

The PowerShell way

TaskCommand
All tasks, excluding Microsoft’s ownGet-ScheduledTask | Where TaskPath -notlike "\Microsoft\*"
Last result and next runGet-ScheduledTask "Nightly Report" | Get-ScheduledTaskInfo
Everything that failed last timeGet-ScheduledTask | Get-ScheduledTaskInfo | Where LastTaskResult -ne 0
Run nowStart-ScheduledTask -TaskName "Nightly Report"
StopStop-ScheduledTask -TaskName "Nightly Report"
Disable or enableDisable-ScheduledTask, Enable-ScheduledTask
RemoveUnregister-ScheduledTask -TaskName "Nightly Report" -Confirm:$false
Export a definitionExport-ScheduledTask -TaskName "Nightly Report" | Out-File task.xml

Creating one properly, with an action, a trigger and a principal:

$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\scripts\report.ps1" -WorkingDirectory "C:\scripts"
$trigger = New-ScheduledTaskTrigger -Daily -At 02:00
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 2) -MultipleInstances IgnoreNew
Register-ScheduledTask -TaskName "Nightly Report" -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force
WorkingDirectory is the Start in box. It is the single most common reason a script works in a console and fails as a task, because a relative path inside the script resolves against C:\Windows\System32 instead of the script’s own folder.

Last result codes

CodeMeaning
0x0Completed successfully
0x1Generic failure. Usually the program’s own exit code, not the scheduler’s.
0x41300Ready, waiting for its next scheduled time
0x41301Currently running
0x41302Disabled
0x41303Has never run
0x41304No future runs scheduled
0x41306Terminated by the user or by the time limit
0x8004131FAn instance is already running, and the policy said do not start another
0x80070002File not found. Check the path in the action.
0x8007010BInvalid directory. The Start in value is wrong.
0x80070005Access denied. Account rights, or the run level.
0x800704DDThe account is not logged on, and the task needs an interactive session
0x800710E0The request was refused, typically power or idle conditions
Anything starting 0x4130 is a state, not an error. Those codes describe where the task is in its life cycle. Real failures come back as 0x8007 or as the program’s own non-zero exit code.

Works by hand, fails as a task

CauseFix
Relative paths in the scriptSet WorkingDirectory, or use absolute paths everywhere
Script file passed directlyCall powershell.exe -File, never the .ps1 on its own
Execution policy-ExecutionPolicy Bypass in the arguments
Profile not loaded, modules missing-NoProfile plus an explicit Import-Module in the script
Mapped drives are not thereDrive letters belong to an interactive session. Use UNC paths.
Runs only when the user is logged onChoose “run whether user is logged on or not”
That option then fails with 0x80070005The account needs the Log on as a batch job right
Service account password changedRe-enter it: the task stores it, and nothing reminds you
Needs elevation/rl HIGHEST, or -RunLevel Highest
32-bit versus 64-bitCall %SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe from a 32-bit context
Task never starts on a laptopPower conditions in the task settings, on battery it is skipped
Two runs overlap-MultipleInstances IgnoreNew and an execution time limit
Where to lookWhat
Event logMicrosoft-Windows-TaskScheduler/Operational, enable it if it is off
Task failed to startEvent 101
Action failed to startEvent 103, carries the path it tried
Action finishedEvent 201, carries the return code
Wrong credentials or missing batch rightEvent 332
The task definitions themselvesC:\Windows\System32\Tasks\, plain XML files

FAQ

The task says it succeeded, but nothing happened.
0x0 means the scheduler started the program and it exited cleanly. If the script itself failed silently, the task cannot know. Add a transcript with Start-Transcript, or write to a log file inside the script, and read event 201 for the actual return code.
Which account should a scheduled job use?
SYSTEM when the job stays on the machine: no password to expire, and no interactive session needed. A domain service account when it must reach network resources as itself, and then give it Log on as a batch job and plan for the password. A group managed service account avoids the password problem entirely.
How do I copy a task to twenty servers?
Export once with schtasks /query /tn "Name" /xml, then import with /create /xml on each machine, supplying /ru and /rp because the password is never exported. In PowerShell, Export-ScheduledTask and Register-ScheduledTask -Xml do the same over remoting.
Can a task run when an event appears in the log?
Yes, with /sc ONEVENT and an XPath query, the same syntax the Event Viewer filter produces. It is a reasonable trigger for something rare and important, and a poor one for a noisy event, since each occurrence starts the task.
Task Scheduler or a service?
A task for anything periodic, a service for anything that must always be running. If you find yourself scheduling a job every minute to check whether something is alive, you have written a service the hard way.