cheat sheet

schtasks

Create, query, run, end, and delete scheduled tasks on local or remote Windows machines from the command prompt — the scripting interface to Windows Task Scheduler.

schtasks — Task Scheduler CLI

What it is

schtasks is the built-in Windows command-line interface to the Task Scheduler service — it lets you create, query, change, run, end, and delete scheduled tasks without opening the GUI. Tasks can trigger on a schedule (MINUTE, HOURLY, DAILY, WEEKLY, MONTHLY, ONCE), at events (ONLOGON, ONIDLE, ONSTART), or at specific times. Use schtasks in deployment scripts to install maintenance jobs, in CI/CD to register build agents, or anywhere you need a scriptable task scheduler. The PowerShell equivalent is the ScheduledTasks module (Register-ScheduledTask, Get-ScheduledTask).

Availability

schtasks ships as C:\Windows\System32\schtasks.exe on Windows XP and later.

cmd
schtasks /?

Output:

sql
SCHTASKS /parameter [arguments]

Description:
    Enables an administrator to create, delete, query, change, run and
    end scheduled tasks on a local or remote system. ...

Parameter List:
    /Create         Creates a new scheduled task.
    /Delete         Deletes the scheduled task(s).
    /Query          Displays all scheduled tasks.
    /Change         Changes the properties of scheduled task.
    /Run            Runs the scheduled task immediately.
    /End            Stops the currently running scheduled task.
    /ShowSid        Shows the security identifier corresponding to a
                    scheduled task name.

Syntax

cmd
schtasks /Create [options]
schtasks /Query  [options]
schtasks /Run    /TN taskname [/S host]
schtasks /End    /TN taskname [/S host]
schtasks /Delete /TN taskname [/F]
schtasks /Change /TN taskname [options]

Output: (varies by sub-command)

Essential options

OptionMeaning
/TN nameTask name (path-like: \Folder\TaskName)
/TR commandTask run — the command to execute
/SC scheduleSchedule type: MINUTE, HOURLY, DAILY, WEEKLY, MONTHLY, ONCE, ONLOGON, ONIDLE, ONSTART
/MO modifierModifier for the schedule (e.g. every N minutes with /SC MINUTE /MO 30)
/ST timeStart time in HH:MM format
/SD dateStart date (default: today)
/ED dateEnd date
/RU userRun-as user account (SYSTEM, LOCALSERVICE, or a username)
/RP passwordPassword for the run-as account
/RL HIGHRun with highest privileges
/FForce — suppress warnings, overwrite existing task
/S hostTarget a remote machine
/FO formatQuery output format: TABLE, LIST, CSV
/NHNo header row in query output
/VVerbose query output
/ZDelete task after final run

Creating a scheduled task

/Create registers a new task. At minimum, specify /TN (name), /TR (command), and /SC (schedule).

cmd
schtasks /Create /TN "MyApp\DailyBackup" /TR "C:\Scripts\backup.bat" /SC DAILY /ST 02:00 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "MyApp\DailyBackup" has successfully been created.
cmd
rem Run every 15 minutes
schtasks /Create /TN "MyApp\HealthCheck" /TR "C:\Scripts\health.bat" /SC MINUTE /MO 15 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "MyApp\HealthCheck" has successfully been created.

Querying scheduled tasks

/Query lists tasks. /FO CSV /NH produces machine-readable output suitable for scripting.

cmd
schtasks /Query /FO TABLE

Output:

ini
Folder: \
TaskName                          Next Run Time          Status
================================= ====================== ===============
\MyApp\DailyBackup                4/29/2026 2:00:00 AM   Ready
\MyApp\HealthCheck                4/28/2026 2:15:00 PM   Ready
cmd
rem Query a specific task with full details
schtasks /Query /TN "MyApp\DailyBackup" /FO LIST /V

Output:

yaml
Folder: \MyApp
HostName:                             MYHOST
TaskName:                             \MyApp\DailyBackup
Next Run Time:                        4/29/2026 2:00:00 AM
Status:                               Ready
Logon Mode:                           Service Account
Last Run Time:                        4/28/2026 2:00:02 AM
Last Result:                          0
Author:                               MYHOST\alicedev
Task To Run:                          C:\Scripts\backup.bat
Run As User:                          SYSTEM
Schedule Type:                        Daily
Start Time:                           2:00:00 AM

Running a task immediately

/Run triggers a task right away regardless of its schedule — useful for testing or manual invocation.

cmd
schtasks /Run /TN "MyApp\DailyBackup"

Output:

vbnet
SUCCESS: Attempted to run the scheduled task "MyApp\DailyBackup".

Ending a running task

/End sends a termination signal to a currently executing task instance.

cmd
schtasks /End /TN "MyApp\DailyBackup"

Output:

vbnet
SUCCESS: The scheduled task "MyApp\DailyBackup" has been terminated successfully.

Changing task properties

/Change modifies an existing task's command, schedule, or run-as credentials without re-creating it.

cmd
rem Update the command
schtasks /Change /TN "MyApp\DailyBackup" /TR "C:\Scripts\backup_v2.bat"

Output:

vbnet
SUCCESS: The parameters of scheduled task "MyApp\DailyBackup" have been changed.
cmd
rem Disable a task
schtasks /Change /TN "MyApp\HealthCheck" /DISABLE

Output:

vbnet
SUCCESS: The parameters of scheduled task "MyApp\HealthCheck" have been changed.
cmd
rem Re-enable it
schtasks /Change /TN "MyApp\HealthCheck" /ENABLE

Output:

vbnet
SUCCESS: The parameters of scheduled task "MyApp\HealthCheck" have been changed.

Deleting a task

/Delete /F removes the task without prompting for confirmation.

cmd
schtasks /Delete /TN "MyApp\HealthCheck" /F

Output:

vbnet
SUCCESS: The scheduled task "MyApp\HealthCheck" was successfully deleted.

One-time and event-based triggers

/SC ONCE runs the task exactly once at the specified date and time. ONLOGON fires whenever any user logs on; ONSTART fires at system startup.

cmd
rem Run once at a specific date/time
schtasks /Create /TN "OneTime\Maintenance" /TR "C:\Scripts\maint.bat" /SC ONCE /SD 04/30/2026 /ST 22:00 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "OneTime\Maintenance" has successfully been created.
cmd
rem Run at every logon
schtasks /Create /TN "Startup\NotifyUser" /TR "C:\Scripts\notify.bat" /SC ONLOGON /RU alicedev /RP * /F

Output:

vbnet
SUCCESS: The scheduled task "Startup\NotifyUser" has successfully been created.

Remote task management

/S targets a remote machine. Requires appropriate DCOM permissions and network access.

cmd
schtasks /Query /S myhost /FO LIST /TN "MyApp\DailyBackup"

Output:

makefile
HostName:      MYHOST
TaskName:      \MyApp\DailyBackup
Status:        Ready
...

Common pitfalls

  1. Task name must include folder path — names with backslash-separated folders (\MyApp\TaskName) are fine; bare names without a leading \ go in the root folder but may collide with system tasks.
  2. /RU SYSTEM requires no /RP — supplying a password for SYSTEM causes an error; omit /RP or use /RP "".
  3. /RL HIGH does not imply SYSTEM privileges — it sets the task to run with the highest available token for the specified user; for true SYSTEM level, use /RU SYSTEM.
  4. /SC ONCE task does not repeat — after it fires, the task shows "Disabled" state; use /SC DAILY or another recurring type if repeat is needed.
  5. Output timestamps depend on localeschtasks /Query /FO CSV date fields use the system locale; parse with care in international environments.
  6. Task deletion vs disabling — prefer /Change /TN x /DISABLE over /Delete if you may want to re-enable later; deleted tasks cannot be recovered.

Real-world recipes

Install a daily log-rotation task

cmd
schtasks /Create ^
    /TN "Ops\RotateLogs" ^
    /TR "C:\Scripts\rotate_logs.bat" ^
    /SC DAILY ^
    /ST 00:30 ^
    /RU SYSTEM ^
    /RL HIGH ^
    /F

Output:

vbnet
SUCCESS: The scheduled task "Ops\RotateLogs" has successfully been created.

Query all tasks and export to CSV

cmd
schtasks /Query /FO CSV /NH > C:\Audit\tasks_%COMPUTERNAME%.csv
echo Saved to C:\Audit\tasks_%COMPUTERNAME%.csv

Output:

css
Saved to C:\Audit\tasks_MYHOST.csv

Check last run result for a task

cmd
schtasks /Query /TN "MyApp\DailyBackup" /FO LIST /V | findstr "Last Result"

Output:

sql
Last Result:                          0

A result of 0 means success; any non-zero value is an error code.

Delete all tasks in a folder

cmd
schtasks /Delete /TN "\MyApp\*" /F

Output:

vbnet
SUCCESS: The scheduled task "\MyApp\DailyBackup" was successfully deleted.
SUCCESS: The scheduled task "\MyApp\HealthCheck" was successfully deleted.

Schedule types in depth

Each /SC value targets a different trigger model and pairs with a different set of modifier flags. Getting the modifier right is the bulk of schtasks /Create complexity.

/SC valueWhen it firesRequired modifierOptional flags
MINUTEEvery N minutes/MO N (1–1439)/ST, /SD, /ED, /DU
HOURLYEvery N hours/MO N (1–23)/ST, /SD, /ED, /DU
DAILYEvery N days/MO N (default 1)/ST, /SD, /ED
WEEKLYSelected weekdays/MO N + /D MON,TUE,…/ST, /SD, /ED
MONTHLYSelected day-of-month/MO N + /D N or /D FIRST,LAST,WEEKDAY,… + /M JAN,FEB,…/ST
ONCESingle firenone/SD, /ST (both required)
ONSTARTAt system bootnone/DELAY (HHHH:MM)
ONLOGONAt any user logonnone/RU user to limit
ONIDLEWhen system idle/I N minutes idlenone
ONEVENTOn Event Log event/EC channel /MO XPathnone
cmd
rem Run every 30 minutes between 9 am and 5 pm
schtasks /Create /TN "Ops\PollFeeds" /TR "C:\Scripts\poll.bat" ^
    /SC MINUTE /MO 30 /ST 09:00 /DU 0008:00 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "Ops\PollFeeds" has successfully been created.
cmd
rem Weekly: Monday + Friday at 03:15
schtasks /Create /TN "Ops\WeeklyReport" /TR "C:\Scripts\weekly.bat" ^
    /SC WEEKLY /D MON,FRI /ST 03:15 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "Ops\WeeklyReport" has successfully been created.
cmd
rem Monthly: first Monday of every month at 02:00
schtasks /Create /TN "Ops\MonthlyAudit" /TR "C:\Scripts\audit.bat" ^
    /SC MONTHLY /MO FIRST /D MON /ST 02:00 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "Ops\MonthlyAudit" has successfully been created.
cmd
rem One-off run 60 seconds from now (date and time must be future)
schtasks /Create /TN "OneShot\Test" /TR "C:\Scripts\test.bat" ^
    /SC ONCE /SD 05/25/2026 /ST 14:31 /RU SYSTEM /F

Output:

vbnet
SUCCESS: The scheduled task "OneShot\Test" has successfully been created.

Date and time format quirks

/SD and /ST parse according to the system localeMM/DD/YYYY on US-English Windows, DD/MM/YYYY on UK-English. This is a recurring source of mass-deployment bugs.

cmd
rem US: month-first
schtasks /Create … /SD 06/15/2026 /ST 14:00 …

rem UK / EU: day-first
schtasks /Create … /SD 15/06/2026 /ST 14:00 …

Output: (none — syntax illustration with placeholders, not executable as-is)

Two ways to defuse this:

  1. Use PowerShell Register-ScheduledTask (next section) — the New-ScheduledTaskTrigger -At cmdlet accepts a culture-invariant DateTime.
  2. Detect the locale and format conditionally:
cmd
for /f "tokens=2 delims==" %%G in ('wmic os get locale /value ^| find "="') do set LOC=%%G
echo Detected locale code: %LOC%

Output:

yaml
Detected locale code: 0409

XML import/export — the only stable scripting path

Beyond the basic verbs, the most powerful interface to Task Scheduler is the XML form of a task definition. /Query /XML exports the full definition; /Create /XML imports one verbatim. XML preserves features the command-line flags cannot express: multiple triggers, conditional power-source rules, idle re-evaluation, repetition intervals, and the V2 task definition's RestartInterval/RestartCount.

cmd
rem Export an existing task to XML
schtasks /Query /TN "MyApp\DailyBackup" /XML > backup.xml

Output: (none — written to backup.xml)

xml
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2026-04-28T02:00:00</StartBoundary>
      <ScheduleByDay><DaysInterval>1</DaysInterval></ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
  </Settings>
  <Actions>
    <Exec><Command>C:\Scripts\backup.bat</Command></Exec>
  </Actions>
</Task>
cmd
rem Edit backup.xml, then import to create a new task
schtasks /Create /TN "MyApp\DailyBackupV2" /XML backup.xml /F

Output:

vbnet
SUCCESS: The scheduled task "MyApp\DailyBackupV2" has successfully been created.

XML is also how you express repetition (e.g., "run every 5 minutes for 1 hour"), conditional triggers (only run if on AC power), and multi-action tasks (run command A, then command B). None of these are reachable via the bare command-line flags.

xml
<!-- Snippet: repeat every 5 min for 1 hour -->
<CalendarTrigger>
  <Repetition>
    <Interval>PT5M</Interval>
    <Duration>PT1H</Duration>
  </Repetition>
  <StartBoundary>2026-05-25T09:00:00</StartBoundary>
  <ScheduleByDay><DaysInterval>1</DaysInterval></ScheduleByDay>
</CalendarTrigger>

PowerShell ScheduledTasks module

The ScheduledTasks module (in-box since Windows 8/Server 2012) is the modern interface. It composes naturally with the rest of PowerShell, accepts proper DateTime objects, and exposes settings the CLI does not.

schtasksPowerShell
schtasks /Create …Register-ScheduledTask
schtasks /QueryGet-ScheduledTask
schtasks /Query /VGet-ScheduledTaskInfo
schtasks /Run /TN …Start-ScheduledTask
schtasks /End /TN …Stop-ScheduledTask
schtasks /Change …Set-ScheduledTask
schtasks /Delete /TN …Unregister-ScheduledTask
schtasks /ChangeFolder (n/a)Move-ScheduledTask (n/a — re-register)

Build and register a task with cmdlets

powershell
$action  = New-ScheduledTaskAction -Execute 'C:\Scripts\backup.bat'
$trigger = New-ScheduledTaskTrigger -Daily -At 2:00am
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
    -StartWhenAvailable `
    -DontStopIfGoingOnBatteries `
    -AllowStartIfOnBatteries `
    -RestartCount 3 `
    -RestartInterval (New-TimeSpan -Minutes 5)

Register-ScheduledTask -TaskName 'MyApp\DailyBackup' -TaskPath '\MyApp\' `
    -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force

Output:

diff
TaskPath              TaskName               State
--------              --------               -----
\MyApp\               DailyBackup            Ready

Compose multiple triggers and actions

schtasks /Create can register exactly one trigger and one action; PowerShell can register an array of each, which collapses to a richer XML.

powershell
$actions = @(
    New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-File C:\Scripts\step1.ps1'
    New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-File C:\Scripts\step2.ps1'
)
$triggers = @(
    New-ScheduledTaskTrigger -Daily -At 3:00am
    New-ScheduledTaskTrigger -AtStartup
)
Register-ScheduledTask -TaskName 'Ops\Multi' -Action $actions -Trigger $triggers `
    -RunLevel Highest -User 'SYSTEM' -Force

Output:

diff
TaskPath  TaskName  State
--------  --------  -----
\         Ops\Multi Ready

Inspecting state and last result

powershell
Get-ScheduledTask -TaskName 'DailyBackup' | Get-ScheduledTaskInfo

Output:

yaml
LastRunTime        : 5/24/2026 2:00:00 AM
LastTaskResult     : 0
NextRunTime        : 5/25/2026 2:00:00 AM
NumberOfMissedRuns : 0
TaskName           : DailyBackup
TaskPath           : \MyApp\

A LastTaskResult of 0 is success. Common non-zero codes:

CodeMeaning
0x41301 (267009)Task currently running
0x41303 (267011)Task hasn't run yet
0x80070002File not found — /TR path is wrong
0x800704DD"The operation being requested was not performed because the user has not logged on" — common with ONLOGON/non-SYSTEM tasks
0xC000013AUser aborted (Ctrl+C or task ended)

Conditional and event-driven triggers

powershell
# Trigger off an Event Log entry — modern way to do "ONEVENT"
$xml = @'
<QueryList><Query Id="0" Path="System">
  <Select Path="System">
    *[System[Provider[@Name='Service Control Manager'] and EventID=7034]]
  </Select>
</Query></QueryList>
'@
$trigger = New-CimInstance -ClassName MSFT_TaskEventTrigger `
    -ClientOnly -Namespace ROOT/Microsoft/Windows/TaskScheduler `
    -Property @{ Enabled = $true; Subscription = $xml }

$action = New-ScheduledTaskAction -Execute 'C:\Scripts\on_service_crash.bat'

Register-ScheduledTask -TaskName 'Ops\OnServiceCrash' `
    -Action $action -Trigger $trigger -User 'SYSTEM' -RunLevel Highest -Force

Output:

diff
TaskPath  TaskName             State
--------  --------             -----
\         Ops\OnServiceCrash   Ready

That recipe — a task that fires whenever the Service Control Manager logs event 7034 ("service terminated unexpectedly") — is impossible with the bare schtasks /Create flags but trivial via the PowerShell module's XML-flavoured trigger.

Working with the Task Scheduler library directly

For anything the CIM module can't express, drop to the underlying COM API. Both PowerShell and VBScript can use it.

powershell
$svc = New-Object -ComObject Schedule.Service
$svc.Connect()
$folder = $svc.GetFolder('\MyApp')
$folder.GetTasks(0) | ForEach-Object {
    "{0,-32} state={1} last={2}" -f $_.Name, $_.State, $_.LastRunTime
}

Output:

ini
DailyBackup                      state=3 last=5/24/2026 2:00:00 AM
HealthCheck                      state=3 last=5/24/2026 2:15:00 PM

State codes from the COM API:

CodeMeaning
0Unknown
1Disabled
2Queued
3Ready
4Running

This is the same API the Task Scheduler MMC snap-in uses; useful when you need to drive features not exposed by either schtasks.exe or the PowerShell module.

Service Account selection and Run Level

/RU (Run As User) plus /RL (Run Level) defines the security context. Available identities:

/RUBehaviour
SYSTEM (alias NT AUTHORITY\SYSTEM)Maximum privilege; no password needed; cannot interact with desktop
LOCALSERVICEMinimal local-only privilege; no password
NETWORKSERVICEMinimal but uses machine account on network; no password
domain\userThe user's privileges; /RP password or interactive prompt
INTERACTIVE (default)The logged-on user; only fires when someone is logged in

/RL modifies the integrity level the task runs at:

  • /RL LIMITED (default) — Medium integrity; subject to UAC for protected operations.
  • /RL HIGHEST — Full elevated token for the user; UAC bypass; equivalent to "Run as administrator".

A common pitfall is assuming /RL HIGHEST makes any task SYSTEM-like. It does not — it merely elevates the chosen user. For real OS-level rights you must combine /RU SYSTEM and /RL HIGHEST.

cmd
schtasks /Create /TN "Ops\Privileged" /TR "C:\Scripts\admin.bat" ^
    /SC ONCE /SD 01/01/2099 /ST 00:00 ^
    /RU SYSTEM /RL HIGHEST /F

Output:

vbnet
SUCCESS: The scheduled task "Ops\Privileged" has successfully been created.

Storing a domain password with /RP writes the credential into the Task Scheduler's protected store. The credential is encrypted with the machine's DPAPI master key — secure against casual users but recoverable by anyone with administrative access to the machine. For sensitive accounts, prefer a Group Managed Service Account (gMSA) with /RU "MYDOMAIN\svc_account$" /RP "".

Cron equivalence and translation

Coming from Linux, the canonical scheduler is cron (see the cron deep-dive). Task Scheduler is more expressive — it has triggers other than time — but the time-based piece maps directly. Translation table for common cron expressions:

CronschtasksPowerShell
0 2 * * * (daily 02:00)/SC DAILY /ST 02:00-Daily -At 2:00am
*/15 * * * * (every 15 min)/SC MINUTE /MO 15-Once -At now -RepetitionInterval (New-TimeSpan -Minutes 15) -RepetitionDuration ([TimeSpan]::MaxValue)
0 3 * * 1 (Mondays 03:00)/SC WEEKLY /D MON /ST 03:00-Weekly -DaysOfWeek Monday -At 3:00am
0 4 1 * * (1st of month 04:00)/SC MONTHLY /D 1 /ST 04:00-Monthly -DaysOfMonth 1 -At 4:00am
0 5 * * 1-5 (weekday 05:00)/SC WEEKLY /D MON,TUE,WED,THU,FRI /ST 05:00-Weekly -DaysOfWeek Monday,Tuesday,…
@reboot/SC ONSTARTNew-ScheduledTaskTrigger -AtStartup
@hourly/SC HOURLY /MO 1 /ST 00:00-Once -At … -RepetitionInterval (New-TimeSpan -Hours 1) …

Things cron has that schtasks doesn't:

  • @yearly/@annually — emulate with /SC YEARLY (Vista+) or monthly with /M JAN /D 1.
  • Per-user crontabs — Task Scheduler uses ACLs on tasks instead.
  • PATH and environment variables in the crontab — Task Scheduler inherits SYSTEM's environment for SYSTEM tasks; set explicit env vars in the script.

Things schtasks has that cron doesn't:

  • Event-driven (ONEVENT).
  • Idle triggers (ONIDLE).
  • Logon/startup triggers (ONLOGON, ONSTART).
  • Conditional triggers (network available, AC power, user inactive).
  • Automatic restart on failure (RestartCount/RestartInterval in XML).

Logging and history

Per-task History is the most useful audit surface for scheduled work. By default it is disabled at the channel level in modern Windows; enable it once per host before relying on it.

cmd
wevtutil sl Microsoft-Windows-TaskScheduler/Operational /e:true

Output: (no output on success)

After that, the Task Scheduler MMC's "History" tab populates, and Get-WinEvent can query programmatically:

powershell
Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' -MaxEvents 50 |
    Where-Object Id -in 100,200,201,202,203 |
    Select-Object TimeCreated, Id,
        @{N='Task';E={ ($_.Properties | Select-Object -First 1).Value }},
        Message

Output:

arduino
TimeCreated         Id Task                  Message
-----------         -- ----                  -------
5/24/2026 2:00:00  100 \MyApp\DailyBackup    Task Scheduler started "{...}" instance of …
5/24/2026 2:00:00  200 \MyApp\DailyBackup    Task Scheduler launched action "C:\Scripts\backup.bat"
5/24/2026 2:00:02  102 \MyApp\DailyBackup    Task Scheduler successfully finished …

Key event IDs:

IDMeaning
100Task starts
102Task completes
106Task created
108Task triggered
141Task deleted
200Action starts
201Action completes
202Action failed
203Failed to start action
307Missed run (was queued but didn't fire)

Settings hiding in /V output

schtasks /Query /V /FO LIST exposes settings the basic Query doesn't, but several are missing from the CLI altogether and only show up in XML or via the COM API:

  • AllowDemandStart — whether the task accepts /Run
  • AllowHardTerminate — whether the SCM can kill the task tree if it overruns
  • ExecutionTimeLimit — how long before the task is considered hung
  • MultipleInstancesPolicyParallel / Queue / IgnoreNew / StopExisting
  • WakeToRun — wake from sleep to run
  • Hidden — task hidden from the default GUI view
  • Priority — base priority of the task's processes (0–10; default 7)
  • IdleSettings — wait/duration before considering system idle
  • NetworkSettings — wait for a specific network connection name

To inspect these, dump the XML; to set them, either author the XML or use the PowerShell Set-ScheduledTask/Set-ScheduledTaskSettingsSet.

powershell
$task = Get-ScheduledTask -TaskName 'DailyBackup'
$task.Settings

Output:

yaml
MultipleInstances          : IgnoreNew
DisallowStartIfOnBatteries : True
StopIfGoingOnBatteries     : True
AllowHardTerminate         : True
StartWhenAvailable         : True
RunOnlyIfNetworkAvailable  : False
ExecutionTimeLimit         : PT72H
WakeToRun                  : False
Hidden                     : False
Priority                   : 7
IdleSettings               : MSFT_TaskIdleSettings
NetworkSettings            : MSFT_TaskNetworkSettings

Common pitfalls — extended

In addition to the basics above:

  1. /SC ONCE /SD in the past silently succeeds, never runs. A one-shot task whose start time has already passed is created with status "Disabled". Validate the date before creating.
  2. schtasks /Create /TN overwriting an existing task requires /F. Without /F, the create fails with "ERROR: Cannot create a file when that file already exists." — easy to miss in pipeline output.
  3. Spaces in /TR need double quotes around the whole command, plus extra quoting for arguments with spaces. The safest form is /TR "\"C:\Path with space\app.exe\" arg1 arg2".
  4. /RU SYSTEM tasks have no network drive mappings. Mapped drives (Z:\) and user-scoped credentials are gone when running as SYSTEM. Use UNC paths and SYSTEM-readable share permissions.
  5. schtasks /Create /XML validates the XML strictly. Encoding must be UTF-16; saving an XML in UTF-8 (the PowerShell default with > redirection) produces "ERROR: The task XML is malformed." Use Out-File -Encoding Unicode.
  6. /Query without /TN lists root only by default in some locales. Use schtasks /Query /FO LIST /V for the full recursive list; PowerShell's Get-ScheduledTask always recurses.
  7. Task Scheduler service in Manual is the silent killer. If the Task Scheduler service itself isn't running, no tasks fire and no events are logged. Verify with sc query Schedule.
  8. Windows 11 24H2/25H2 regression with manually-added tasks. Several users report that PowerShell-script tasks added by hand on 24H2 silently fail to fire while the same task definition works on 23H2. If a freshly-imaged 24H2 box won't run your task, re-register it via Register-ScheduledTask (rather than the GUI) and confirm the task history channel is enabled — see wevtutil.

Configuration drift and version control

For 2026 environments treating task definitions as code, Export-ScheduledTask produces the same XML form that schtasks /Query /XML does — but composes naturally with Git, PR review, and CI. Round-trip every change through a tracked XML file rather than editing tasks in the GUI:

powershell
# Snapshot every task to a directory of XML files
Get-ScheduledTask | ForEach-Object {
    $safe = ($_.TaskPath + $_.TaskName) -replace '[\\/]', '_'
    Export-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath |
        Out-File -Encoding Unicode "C:\TaskRepo\$safe.xml"
}

Output: (one .xml per task in C:\TaskRepo; commit to Git for drift detection)

Then on the deploy side, re-register from XML:

powershell
Register-ScheduledTask -TaskName 'MyApp\DailyBackup' `
    -Xml (Get-Content C:\TaskRepo\_MyApp_DailyBackup.xml -Raw) -Force

Output:

diff
TaskPath  TaskName    State
--------  --------    -----
\MyApp\   DailyBackup Ready

Real-world deep recipes

Daily-restart pattern with restart-on-failure

powershell
$action = New-ScheduledTaskAction -Execute 'net.exe' -Argument 'stop "MySvc" && net.exe start "MySvc"'
$trigger = New-ScheduledTaskTrigger -Daily -At 4:00am
$settings = New-ScheduledTaskSettingsSet `
    -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 10) `
    -StartWhenAvailable `
    -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName 'Ops\Restart-MySvc' `
    -Action $action -Trigger $trigger -User 'SYSTEM' -RunLevel Highest `
    -Settings $settings -Force

Output:

diff
TaskPath  TaskName             State
--------  --------             -----
\Ops\     Restart-MySvc        Ready

Migrate cron syntax to schtasks programmatically

The translation cron MIN HOUR DOM MON DOWschtasks can be automated for the common cases. Below: a PowerShell helper that maps simple cron expressions to PowerShell triggers.

powershell
function ConvertFrom-Cron {
    param([string]$Cron)
    $f = $Cron -split '\s+'
    if ($f.Count -ne 5) { throw "expected 5 fields, got $($f.Count)" }
    $min, $hour, $dom, $mon, $dow = $f
    if ($min -eq '*' -and $hour -eq '*') {
        return New-ScheduledTaskTrigger -Once -At (Get-Date) `
            -RepetitionInterval (New-TimeSpan -Minutes 1)
    }
    if ($min -match '^\d+$' -and $hour -match '^\d+$' -and $dom -eq '*' -and $mon -eq '*' -and $dow -eq '*') {
        return New-ScheduledTaskTrigger -Daily -At ([datetime]::Today.AddHours($hour).AddMinutes($min))
    }
    throw "cron pattern '$Cron' not yet supported by this stub"
}
ConvertFrom-Cron '30 4 * * *'

Output:

yaml
StartBoundary : 2026-05-25T04:30:00
DaysInterval  : 1

List tasks that haven't run in 30 days

powershell
$cutoff = (Get-Date).AddDays(-30)
Get-ScheduledTask | ForEach-Object {
    $info = $_ | Get-ScheduledTaskInfo
    if ($info.LastRunTime -lt $cutoff) {
        [PSCustomObject]@{
            Path       = $_.TaskPath + $_.TaskName
            LastRun    = $info.LastRunTime
            LastResult = "0x{0:X}" -f $info.LastTaskResult
        }
    }
} | Sort-Object LastRun

Output:

swift
Path                        LastRun              LastResult
----                        -------              ----------
\MyApp\OldStaleTask        1/12/2026 3:00:00 AM  0x0
\Ops\DeprecatedReport      2/04/2026 6:00:00 AM  0x0

Per-host task inventory dump for audit

powershell
Get-ScheduledTask | ForEach-Object {
    $info = $_ | Get-ScheduledTaskInfo
    [PSCustomObject]@{
        Host        = $env:COMPUTERNAME
        Path        = $_.TaskPath
        Name        = $_.TaskName
        State       = $_.State
        Author      = $_.Author
        UserId      = $_.Principal.UserId
        RunLevel    = $_.Principal.RunLevel
        Triggers    = ($_.Triggers | ForEach-Object { $_.GetType().Name }) -join ';'
        Actions     = ($_.Actions  | ForEach-Object { "$($_.Execute) $($_.Arguments)".Trim() }) -join ' | '
        LastRun     = $info.LastRunTime
        LastResult  = "0x{0:X}" -f $info.LastTaskResult
        NextRun     = $info.NextRunTime
    }
} | Export-Csv "C:\Audit\tasks_$env:COMPUTERNAME.csv" -NoTypeInformation

Output: (no console output — written to C:\Audit\tasks_MYHOST.csv)

See also

Sources

learn.microsoft.com — schtasks commands · learn.microsoft.com — ScheduledTasks module · Microsoft Q&A — Windows 11 24H2 Task Scheduler regression