schtasks

The Windows Task Scheduler command — query, create, change, and run scheduled tasks — as a defender's reference, with the task-based persistence and lateral-movement patterns to detect. Click any command to copy it.

Start here

What you're looking at

Scheduled tasks run a program on a trigger — logon, boot, a time, an event, an idle period. That makes them a top persistence spot (MITRE T1053.005) and a quiet lateral-movement path. schtasks.exe is the CLI; the GUI is Task Scheduler; PowerShell has the *-ScheduledTask cmdlets. Pairs with the sc, Registry, and Event IDs sheets.

schtasks /create /tn ... /tr ... /sc ...The shape of a create: /tn task name, /tr the program to run, /sc the schedule. Everything else is modifiers.
Tasks live in foldersTask names are paths — \Microsoft\Windows\... for built-ins. Malware often drops a task in the root (\MyTask) or mimics a Microsoft folder name.
Three places a task existsThe XML in C:\Windows\System32\Tasks\, the registry under ...\Schedule\TaskCache\Tree and \Tasks, plus the SCM view. All three should agree — a mismatch means hiding.
PowerShell equivalentGet-ScheduledTask, Register-ScheduledTask, Get-ScheduledTaskInfo — richer objects, better for scripting a baseline.

Read

Query & inspect

schtasks /queryAll tasks with next run time and status — the quick overview (truncated columns).
schtasks /query /fo LIST /vThe triage staple — verbose list: Task To Run, Run As User, Author, trigger, last/next run, and more, one field per line.
schtasks /query /tn "\MyTask" /fo LIST /vFull detail on one task by name.
schtasks /query /xmlDump every task definition as XML — the complete truth, including the exact command, arguments, and author. Best for diffing.
schtasks /query /tn "\MyTask" /xmlOne task's full XML — read the <Command>, <Arguments>, <Principal>, and <Author>.
schtasks /query /fo CSV /nhCSV with no header — pipe to a file or a spreadsheet for a baseline/diff.
Get-ScheduledTask | Get-ScheduledTaskInfoPowerShell: every task with last run time and result — objects you can filter and sort.
Get-ScheduledTask | ? {$_.Author -notlike 'Microsoft*'}Narrow to non-Microsoft authors fast — cuts the noise to what someone added.

Change

Create a task

The high-signal section. A new task that runs an interpreter, lives in the root folder, or fires at logon/boot is classic persistence — treat creates as events to investigate. Logs as Event 4698 and TaskScheduler 106.

schtasks /create /tn "Updater" /tr "c:\app.exe" /sc onlogon/sc is the schedule: minute, hourly, daily, weekly, onlogon, onstart, onidle, once, onevent.
schtasks /create /tn X /tr "powershell -enc ..." /sc onlogonA task whose /tr is powershell, cmd, wscript, mshta, or rundll32 — especially encoded — is almost always malicious persistence.
schtasks /create ... /ru SYSTEM/ru sets the run-as account. SYSTEM (needs admin) runs the payload as the highest-priv account — a privilege tell. /rp supplies a password.
schtasks /create ... /sc onstart /ru SYSTEMRun at every boot as SYSTEM — the most durable persistence combination.
schtasks /create ... /sc onevent /ec Security /mo "*[System[(EventID=4624)]]"Trigger on a Windows event (/ec channel, /mo XPath) — e.g. fire on each logon. A sneaky, less-watched trigger.
schtasks /create ... /sc minute /mo 5/mo = the modifier/interval — here "every 5 minutes." Short intervals on an odd task look like beaconing.
schtasks /create ... /xml task.xmlCreate straight from an XML definition — lets an attacker set fields the CLI flags don't expose. The XML is worth reading.
schtasks /create ... /f/f forces (overwrites an existing task with no prompt) — used to silently replace a legit task.

The baseline move: schtasks /query /xml (or Get-ScheduledTask) saved to a file on a known-good host is your allow-list. Diff it — a new task, a non-Microsoft author, an interpreter in <Command>, or a logon/boot trigger is what you're hunting.

Change

Change, run & delete

schtasks /change /tn "\MyTask" /tr "c:\evil.exe"Re-point an existing task's program — hijack a trusted task's name while swapping what it runs. Logs as 4702. Compare to baseline.
schtasks /change /tn X /ru SYSTEM /rp ""Change the run-as account or password of a task — escalation or re-enabling a disabled one.
schtasks /run /tn "\MyTask"Run a task immediately, on demand — an attacker triggering their payload without waiting for the schedule.
schtasks /end /tn "\MyTask"Stop a running task instance.
schtasks /change /tn X /disable  ·  /enableDisable or enable a task — disabling a defensive maintenance task is an evasion move.
schtasks /delete /tn "\MyTask" /fDelete a task — remediation, or an attacker cleaning up. Logs as 4699. Export the XML first.

Forensics

Artifacts on disk & the hiding trick

Where a task really lives — and how one gets hidden from schtasks and the GUI.

C:\Windows\System32\Tasks\One XML file per task (folders mirror the task tree). Read the <Command>, <Author>, <Date>, and trigger. File create/modify times here are strong timeline evidence.
...\CurrentVersion\Schedule\TaskCache\TreeRegistry: one subkey per task with its GUID. The authoritative list the service reads.
...\TaskCache\Tasks\{GUID}Per-GUID detail — Actions (the command, binary), Path, and the SD (security descriptor) value.
Hidden-task trickDeleting the SD value under TaskCache\Tree\<task> makes the task vanish from schtasks and the GUI but it still runs. Compare Tree vs Tasks vs the XML folder — a task in one but not the others is hidden.
Microsoft-Windows-TaskScheduler/OperationalThe dedicated log: 106 registered, 140 updated, 141 deleted, 200/201 action run/completed. Enable it if it's off.
Security log — 4698 / 4702 / 4699With auditing on: 4698 created, 4702 updated, 4699 deleted, 4700/4701 enabled/disabled. The event body carries the full task XML.

Fleet

Remote hosts

schtasks /query /s SRV01 /fo LIST /vQuery a remote host's tasks (needs rights + RPC reachable) — triage without logging in.
schtasks /query /s SRV01 /u DOMAIN\admin /pSupply alternate credentials for the remote query/create.
schtasks /create /s SRV01 /tn X /tr "..." /ru SYSTEMCreate a task on a remote machine — a well-worn remote-exec / lateral-movement technique. Alert on remote 4698.
schtasks /run /s SRV01 /tn XTrigger a task on a remote host — fire the payload you just planted.

Put it together

SOC one-liners

Quick reads against a live box. The PowerShell cmdlets give you cleaner filtering for most of these.

schtasks /query /fo LIST /v | findstr /i "Task To Run"Every task's command in a flat list — eyeball for temp, appdata, users, public, or an interpreter.
Get-ScheduledTask | % { $_.Actions } | ? {$_.Execute -match 'powershell|cmd|wscript|mshta|rundll32|regsvr32'}Tasks that launch an interpreter / LOLBin — the usual malicious-task signature.
Get-ScheduledTask | ? {$_.Actions.Execute -match 'temp|appdata|\\users\\|programdata|public'}Tasks whose binary sits in a user-writable path — strong persistence flag.
Get-ScheduledTask | ? {$_.Principal.UserId -eq 'SYSTEM' -and $_.Author -notlike 'Microsoft*'}Non-Microsoft tasks running as SYSTEM — short list, high interest.
Get-ScheduledTask | ? {$_.TaskPath -eq '\'} Tasks sitting in the root folder (not under \Microsoft\) — where dropped tasks tend to land.
dir "C:\Windows\System32\Tasks" /s /b | sortList the task XML files on disk — then diff against schtasks /query to catch a hidden (SD-deleted) task.
Get-WinEvent -FilterHashtable @{LogName='Security';Id=4698} -MaxEvents 50Recent task-creation events, with the full task XML in the message — hunt new persistence after an alert.

Detection, restated: task created/updated/deleted logs as Security 4698 / 4702 / 4699 and TaskScheduler 106 / 140 / 141; schtasks.exe in a command line (4688 / Sysmon 1) with /create, /change /tr, or /s \\ is the alert — above all with an interpreter in the task action or an odd parent process.