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.
schtasks /?
Output:
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
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
| Option | Meaning |
|---|---|
/TN name | Task name (path-like: \Folder\TaskName) |
/TR command | Task run — the command to execute |
/SC schedule | Schedule type: MINUTE, HOURLY, DAILY, WEEKLY, MONTHLY, ONCE, ONLOGON, ONIDLE, ONSTART |
/MO modifier | Modifier for the schedule (e.g. every N minutes with /SC MINUTE /MO 30) |
/ST time | Start time in HH:MM format |
/SD date | Start date (default: today) |
/ED date | End date |
/RU user | Run-as user account (SYSTEM, LOCALSERVICE, or a username) |
/RP password | Password for the run-as account |
/RL HIGH | Run with highest privileges |
/F | Force — suppress warnings, overwrite existing task |
/S host | Target a remote machine |
/FO format | Query output format: TABLE, LIST, CSV |
/NH | No header row in query output |
/V | Verbose query output |
/Z | Delete task after final run |
Creating a scheduled task
/Create registers a new task. At minimum, specify /TN (name), /TR (command), and /SC (schedule).
schtasks /Create /TN "MyApp\DailyBackup" /TR "C:\Scripts\backup.bat" /SC DAILY /ST 02:00 /RU SYSTEM /F
Output:
SUCCESS: The scheduled task "MyApp\DailyBackup" has successfully been created.
rem Run every 15 minutes
schtasks /Create /TN "MyApp\HealthCheck" /TR "C:\Scripts\health.bat" /SC MINUTE /MO 15 /RU SYSTEM /F
Output:
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.
schtasks /Query /FO TABLE
Output:
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
rem Query a specific task with full details
schtasks /Query /TN "MyApp\DailyBackup" /FO LIST /V
Output:
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.
schtasks /Run /TN "MyApp\DailyBackup"
Output:
SUCCESS: Attempted to run the scheduled task "MyApp\DailyBackup".
Ending a running task
/End sends a termination signal to a currently executing task instance.
schtasks /End /TN "MyApp\DailyBackup"
Output:
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.
rem Update the command
schtasks /Change /TN "MyApp\DailyBackup" /TR "C:\Scripts\backup_v2.bat"
Output:
SUCCESS: The parameters of scheduled task "MyApp\DailyBackup" have been changed.
rem Disable a task
schtasks /Change /TN "MyApp\HealthCheck" /DISABLE
Output:
SUCCESS: The parameters of scheduled task "MyApp\HealthCheck" have been changed.
rem Re-enable it
schtasks /Change /TN "MyApp\HealthCheck" /ENABLE
Output:
SUCCESS: The parameters of scheduled task "MyApp\HealthCheck" have been changed.
Deleting a task
/Delete /F removes the task without prompting for confirmation.
schtasks /Delete /TN "MyApp\HealthCheck" /F
Output:
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.
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:
SUCCESS: The scheduled task "OneTime\Maintenance" has successfully been created.
rem Run at every logon
schtasks /Create /TN "Startup\NotifyUser" /TR "C:\Scripts\notify.bat" /SC ONLOGON /RU alicedev /RP * /F
Output:
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.
schtasks /Query /S myhost /FO LIST /TN "MyApp\DailyBackup"
Output:
HostName: MYHOST
TaskName: \MyApp\DailyBackup
Status: Ready
...
Common pitfalls
- 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. /RU SYSTEMrequires no/RP— supplying a password for SYSTEM causes an error; omit/RPor use/RP ""./RL HIGHdoes 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./SC ONCEtask does not repeat — after it fires, the task shows "Disabled" state; use/SC DAILYor another recurring type if repeat is needed.- Output timestamps depend on locale —
schtasks /Query /FO CSVdate fields use the system locale; parse with care in international environments. - Task deletion vs disabling — prefer
/Change /TN x /DISABLEover/Deleteif you may want to re-enable later; deleted tasks cannot be recovered.
Real-world recipes
Install a daily log-rotation task
schtasks /Create ^
/TN "Ops\RotateLogs" ^
/TR "C:\Scripts\rotate_logs.bat" ^
/SC DAILY ^
/ST 00:30 ^
/RU SYSTEM ^
/RL HIGH ^
/F
Output:
SUCCESS: The scheduled task "Ops\RotateLogs" has successfully been created.
Query all tasks and export to CSV
schtasks /Query /FO CSV /NH > C:\Audit\tasks_%COMPUTERNAME%.csv
echo Saved to C:\Audit\tasks_%COMPUTERNAME%.csv
Output:
Saved to C:\Audit\tasks_MYHOST.csv
Check last run result for a task
schtasks /Query /TN "MyApp\DailyBackup" /FO LIST /V | findstr "Last Result"
Output:
Last Result: 0
A result of 0 means success; any non-zero value is an error code.
Delete all tasks in a folder
schtasks /Delete /TN "\MyApp\*" /F
Output:
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 value | When it fires | Required modifier | Optional flags |
|---|---|---|---|
MINUTE | Every N minutes | /MO N (1–1439) | /ST, /SD, /ED, /DU |
HOURLY | Every N hours | /MO N (1–23) | /ST, /SD, /ED, /DU |
DAILY | Every N days | /MO N (default 1) | /ST, /SD, /ED |
WEEKLY | Selected weekdays | /MO N + /D MON,TUE,… | /ST, /SD, /ED |
MONTHLY | Selected day-of-month | /MO N + /D N or /D FIRST,LAST,WEEKDAY,… + /M JAN,FEB,… | /ST |
ONCE | Single fire | none | /SD, /ST (both required) |
ONSTART | At system boot | none | /DELAY (HHHH:MM) |
ONLOGON | At any user logon | none | /RU user to limit |
ONIDLE | When system idle | /I N minutes idle | none |
ONEVENT | On Event Log event | /EC channel /MO XPath | none |
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:
SUCCESS: The scheduled task "Ops\PollFeeds" has successfully been created.
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:
SUCCESS: The scheduled task "Ops\WeeklyReport" has successfully been created.
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:
SUCCESS: The scheduled task "Ops\MonthlyAudit" has successfully been created.
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:
SUCCESS: The scheduled task "OneShot\Test" has successfully been created.
Date and time format quirks
/SD and /ST parse according to the system locale — MM/DD/YYYY on US-English Windows, DD/MM/YYYY on UK-English. This is a recurring source of mass-deployment bugs.
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:
- Use PowerShell
Register-ScheduledTask(next section) — theNew-ScheduledTaskTrigger -Atcmdlet accepts a culture-invariantDateTime. - Detect the locale and format conditionally:
for /f "tokens=2 delims==" %%G in ('wmic os get locale /value ^| find "="') do set LOC=%%G
echo Detected locale code: %LOC%
Output:
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.
rem Export an existing task to XML
schtasks /Query /TN "MyApp\DailyBackup" /XML > backup.xml
Output: (none — written to backup.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>
rem Edit backup.xml, then import to create a new task
schtasks /Create /TN "MyApp\DailyBackupV2" /XML backup.xml /F
Output:
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.
<!-- 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.
schtasks | PowerShell |
|---|---|
schtasks /Create … | Register-ScheduledTask |
schtasks /Query | Get-ScheduledTask |
schtasks /Query /V | Get-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
$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:
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.
$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:
TaskPath TaskName State
-------- -------- -----
\ Ops\Multi Ready
Inspecting state and last result
Get-ScheduledTask -TaskName 'DailyBackup' | Get-ScheduledTaskInfo
Output:
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:
| Code | Meaning |
|---|---|
0x41301 (267009) | Task currently running |
0x41303 (267011) | Task hasn't run yet |
0x80070002 | File 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 |
0xC000013A | User aborted (Ctrl+C or task ended) |
Conditional and event-driven triggers
# 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:
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.
$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:
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:
| Code | Meaning |
|---|---|
0 | Unknown |
1 | Disabled |
2 | Queued |
3 | Ready |
4 | Running |
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:
/RU | Behaviour |
|---|---|
SYSTEM (alias NT AUTHORITY\SYSTEM) | Maximum privilege; no password needed; cannot interact with desktop |
LOCALSERVICE | Minimal local-only privilege; no password |
NETWORKSERVICE | Minimal but uses machine account on network; no password |
domain\user | The 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.
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:
SUCCESS: The scheduled task "Ops\Privileged" has successfully been created.
Storing a domain password with
/RPwrites 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:
| Cron | schtasks | PowerShell |
|---|---|---|
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 ONSTART | New-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.
PATHand 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/RestartIntervalin 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.
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:
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:
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:
| ID | Meaning |
|---|---|
100 | Task starts |
102 | Task completes |
106 | Task created |
108 | Task triggered |
141 | Task deleted |
200 | Action starts |
201 | Action completes |
202 | Action failed |
203 | Failed to start action |
307 | Missed 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/RunAllowHardTerminate— whether the SCM can kill the task tree if it overrunsExecutionTimeLimit— how long before the task is considered hungMultipleInstancesPolicy—Parallel/Queue/IgnoreNew/StopExistingWakeToRun— wake from sleep to runHidden— task hidden from the default GUI viewPriority— base priority of the task's processes (0–10; default 7)IdleSettings— wait/duration before considering system idleNetworkSettings— 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.
$task = Get-ScheduledTask -TaskName 'DailyBackup'
$task.Settings
Output:
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:
/SC ONCE /SDin 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.schtasks /Create /TNoverwriting 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.- Spaces in
/TRneed 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". /RU SYSTEMtasks 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.schtasks /Create /XMLvalidates 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." UseOut-File -Encoding Unicode./Querywithout/TNlists root only by default in some locales. Useschtasks /Query /FO LIST /Vfor the full recursive list; PowerShell'sGet-ScheduledTaskalways recurses.- Task Scheduler service in
Manualis the silent killer. If the Task Scheduler service itself isn't running, no tasks fire and no events are logged. Verify withsc query Schedule. - 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 — seewevtutil.
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:
# 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:
Register-ScheduledTask -TaskName 'MyApp\DailyBackup' `
-Xml (Get-Content C:\TaskRepo\_MyApp_DailyBackup.xml -Raw) -Force
Output:
TaskPath TaskName State
-------- -------- -----
\MyApp\ DailyBackup Ready
Real-world deep recipes
Daily-restart pattern with restart-on-failure
$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:
TaskPath TaskName State
-------- -------- -----
\Ops\ Restart-MySvc Ready
Migrate cron syntax to schtasks programmatically
The translation cron MIN HOUR DOM MON DOW → schtasks can be automated for the common cases. Below: a PowerShell helper that maps simple cron expressions to PowerShell triggers.
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:
StartBoundary : 2026-05-25T04:30:00
DaysInterval : 1
List tasks that haven't run in 30 days
$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:
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
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
- sc — Service Control Manager CLI — when you need an always-on background daemon, not a scheduled job.
- tasklist — List Running Processes and taskkill — kill stuck task instances.
- wevtutil — Event Log CLI — enable Task Scheduler history and query event log triggers.
- cron — Time-based job scheduling — Linux equivalent.
- Sysinternals — PsExec, Handle, ProcMon and the Sysadmin Toolkit —
psexecfor ad-hoc one-shot remote execution.
Sources
learn.microsoft.com — schtasks commands · learn.microsoft.com — ScheduledTasks module · Microsoft Q&A — Windows 11 24H2 Task Scheduler regression