Start here
Did it run, and what came back
Get-ScheduledTaskInfoRun it now, without waiting
schtasks /run /tn "Name"Everything on this machine
schtasks /query /fo LIST /vWhy did it fail
TaskScheduler/Operational log
Move a task to another server
/query /xml then /create /xmlWorks 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
| Task | Command |
|---|---|
| All tasks, readable | schtasks /query /fo LIST /v |
| One task in detail | schtasks /query /tn "Nightly Backup" /fo LIST /v |
| Machine readable | schtasks /query /fo CSV /nh |
| Export a task definition | schtasks /query /tn "Nightly Backup" /xml > backup.xml |
| Run now | schtasks /run /tn "Nightly Backup" |
| Stop a running task | schtasks /end /tn "Nightly Backup" |
| Disable without deleting | schtasks /change /tn "Nightly Backup" /disable |
| Re-enable | schtasks /change /tn "Nightly Backup" /enable |
| Delete | schtasks /delete /tn "Nightly Backup" /f |
| Against another machine | schtasks /query /s SRV01 /u DOM\admin /p * |
Creating a task
| Switch | Meaning |
|---|---|
/tn | Task name, and its folder path if you want one |
/tr | What to run, fully qualified |
/sc | Schedule type, see the table below |
/mo | Modifier, the “every n” part |
/st | Start time, 24-hour HH:MM |
/d | Day: MON to SUN, or 1 to 31 for monthly |
/ru | Account to run as. SYSTEM needs no password. |
/rp | Password for that account |
/rl | HIGHEST or LIMITED. Default is LIMITED. |
/f | Overwrite an existing task of the same name |
/i | Idle minutes, required with ONIDLE |
/xml | Create from an exported definition |
| /sc value | When it runs |
|---|---|
MINUTE, HOURLY | Every n minutes or hours, with /mo |
DAILY, WEEKLY, MONTHLY | Every n days, weeks or months |
ONCE | A single run at a date and time |
ONSTART | At every system start |
ONLOGON | When a user logs on |
ONIDLE | After n idle minutes |
ONEVENT | On 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
| Task | Command |
|---|---|
| All tasks, excluding Microsoft’s own | Get-ScheduledTask | Where TaskPath -notlike "\Microsoft\*" |
| Last result and next run | Get-ScheduledTask "Nightly Report" | Get-ScheduledTaskInfo |
| Everything that failed last time | Get-ScheduledTask | Get-ScheduledTaskInfo | Where LastTaskResult -ne 0 |
| Run now | Start-ScheduledTask -TaskName "Nightly Report" |
| Stop | Stop-ScheduledTask -TaskName "Nightly Report" |
| Disable or enable | Disable-ScheduledTask, Enable-ScheduledTask |
| Remove | Unregister-ScheduledTask -TaskName "Nightly Report" -Confirm:$false |
| Export a definition | Export-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
| Code | Meaning |
|---|---|
0x0 | Completed successfully |
0x1 | Generic failure. Usually the program’s own exit code, not the scheduler’s. |
0x41300 | Ready, waiting for its next scheduled time |
0x41301 | Currently running |
0x41302 | Disabled |
0x41303 | Has never run |
0x41304 | No future runs scheduled |
0x41306 | Terminated by the user or by the time limit |
0x8004131F | An instance is already running, and the policy said do not start another |
0x80070002 | File not found. Check the path in the action. |
0x8007010B | Invalid directory. The Start in value is wrong. |
0x80070005 | Access denied. Account rights, or the run level. |
0x800704DD | The account is not logged on, and the task needs an interactive session |
0x800710E0 | The 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
| Cause | Fix |
|---|---|
| Relative paths in the script | Set WorkingDirectory, or use absolute paths everywhere |
| Script file passed directly | Call 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 there | Drive letters belong to an interactive session. Use UNC paths. |
| Runs only when the user is logged on | Choose “run whether user is logged on or not” |
| That option then fails with 0x80070005 | The account needs the Log on as a batch job right |
| Service account password changed | Re-enter it: the task stores it, and nothing reminds you |
| Needs elevation | /rl HIGHEST, or -RunLevel Highest |
| 32-bit versus 64-bit | Call %SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe from a 32-bit context |
| Task never starts on a laptop | Power conditions in the task settings, on battery it is skipped |
| Two runs overlap | -MultipleInstances IgnoreNew and an execution time limit |
| Where to look | What |
|---|---|
| Event log | Microsoft-Windows-TaskScheduler/Operational, enable it if it is off |
| Task failed to start | Event 101 |
| Action failed to start | Event 103, carries the path it tried |
| Action finished | Event 201, carries the return code |
| Wrong credentials or missing batch right | Event 332 |
| The task definitions themselves | C:\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.