Skip to content

Windows Scheduled Task Forensics: The Complete Guide

Scheduled task forensics end to end: task XML files, the TaskCache registry key, legacy .job files and event logs, and how to correlate them in a case.

Published on 7 min read

TL;DR. A Windows scheduled task leaves up to four kinds of evidence: an XML definition in C:\Windows\System32\Tasks, a registry copy in the SOFTWARE hive under TaskCache, sometimes a legacy .job file in C:\Windows\Tasks, and event log records (Security 4698 to 4702, TaskScheduler/Operational 106, 140, 141, 200, 201). Collect all of them, correlate XML with registry by task path, compare them, and treat each suspicious attribute as a lead to verify rather than a verdict.

Scheduled tasks are one of the most common persistence mechanisms on Windows. MITRE ATT&CK tracks them as T1053.005 Scheduled Task, used for persistence, execution and privilege escalation. They are also one of the noisiest places on a clean system: a fresh Windows 11 install registers well over a hundred Microsoft tasks. The investigator's job is to find the handful that do not belong, and to date them.

This guide is the entry point of the series. Each section links to a deeper article.

The four sources of evidence

SourceLocationWhat it gives youDeep dive
Task XMLC:\Windows\System32\Tasks\<folder>\<name> (no extension)Full definition: author, registration date, triggers, principal, settings, actionsTask XML anatomy
TaskCacheHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCacheTree (names, Id, Index, SD), Tasks (path, hash, actions, triggers, run times)TaskCache registry forensics
Legacy .jobC:\Windows\Tasks\*.jobBinary Task Scheduler 1.0 jobs, last run time.job file forensics
Event logsSecurity.evtx, Microsoft-Windows-TaskScheduler%4Operational.evtxWho registered, updated or deleted a task, and when it ranThis article, below

The XML schema is documented by Microsoft in the Task Scheduler Schema reference. The registry layout and the .job format are partly documented: the .job format is specified in MS-TSCH, while the binary values in TaskCache are known mostly from community reverse engineering, notably the cyber.wtf TaskCache analysis and libyal's winreg-kb.

Where each file lives on every Windows version, and how to collect it without losing data, is covered in where scheduled tasks are stored and how to acquire them.

Why the registry matters as much as the XML

Many checklists stop at the XML folder. That is not enough. The Task Scheduler service keeps its own copy of every registered task in the TaskCache key of the SOFTWARE hive, split in two:

  • Tree\<task path> holds one key per task, named like the task, with an Id (the task GUID), an Index and an SD value, the security descriptor that controls who can see and change the task.
  • Tasks\{GUID} holds the task data: Path, URI, Author, Date, Hash, Actions, Triggers and DynamicInfo, a binary value with the task's creation, last run and last result.

Three consequences for an investigation:

  1. Deleting the XML file does not unregister the task. The registry entry, and often the task itself, remains. A task present only in TaskCache is worth a close look.
  2. Removing the SD value hides the task from schtasks /query and the Task Scheduler console. This is the technique Microsoft described for the Tarrask malware in April 2022. See Tarrask and hidden scheduled tasks.
  3. The registry holds execution metadata the XML lacks. DynamicInfo records when the task was created and last run, and the last result code, which the XML never does.

Time, and the trap in the XML

The Date in RegistrationInfo and the StartBoundary of triggers are XML dateTime values. Microsoft's API accepts a UTC offset (YYYY-MM-DDTHH:MM:SS(+-)HH:MM, see Trigger.StartBoundary), but tasks created through the console or schtasks usually store no offset at all: the value is in the machine's local time. Microsoft's own event 4698 example shows it: the event is logged at 2015-09-23T02:03:06Z while the embedded task XML says <Date>2015-09-22T19:03:06.9258653</Date>, seven hours earlier, on a machine in a UTC-7 zone.

TaskCache timestamps (DynamicInfo, key last-write times) are FILETIMEs in UTC. Comparing both for the same task is the simplest way to infer the machine's offset. More on this in task XML anatomy and the StartBoundary glossary entry.

Event logs: useful when they exist

LogEvent IDMeaningNotes
Security4698Scheduled task createdContains the full task XML (Microsoft Learn)
Security4699Task deleted
Security4700 / 4701Task enabled / disabled
Security4702Task updated
TaskScheduler/Operational106Task registeredTask name and registering user, no definition
TaskScheduler/Operational140Task updated
TaskScheduler/Operational141Task deleted
TaskScheduler/Operational200 / 201Action started / completedProof the task actually ran

The Security events require the Audit Other Object Access Events subcategory, which is not enabled by default on most workstations. The Operational channel is the one behind the "Enable All Tasks History" switch in the Task Scheduler console; on many systems it is off or short-lived. Treat missing events as "not recorded", not "did not happen". Researchers have also shown that tasks written straight into the registry can avoid both 4698 and 106 entirely (Binary Defense). If you have the logs, parse them with the EVTX parser and line them up with the task data.

What to look for

A short list, detailed in how to detect malicious scheduled tasks:

  • Commands in user-writable folders: C:\Users\Public, C:\ProgramData, %TEMP%, AppData.
  • Encoded PowerShell (-EncodedCommand) and script hosts or LOLBins such as rundll32, regsvr32, mshta, certutil.
  • Non-Microsoft tasks running as SYSTEM or with HighestAvailable.
  • Tasks at the root of the library or with random-looking names, a pattern Microsoft's own monitoring guidance calls out.
  • Hidden tasks (<Hidden>true</Hidden>) from a non-Microsoft author, and TaskCache entries with no SD value.
  • Mismatches: XML present but no registry entry, registry entry with no XML, or a Hash that does not match the XML on disk.
  • Recent registration dates close to the incident window.

Each item has innocent explanations. Vendor updaters live in ProgramData; IT scripts use -EncodedCommand. The flags narrow the search; your corroboration decides.

A workflow that holds up

  1. Acquire C:\Windows\System32\Tasks (recursive), C:\Windows\SysWOW64\Tasks, C:\Windows\Tasks, the SOFTWARE hive with its .LOG1/.LOG2 transaction logs, and the Security and TaskScheduler/Operational logs. KAPE's ScheduledTasks and RegistryHivesSystem targets cover the files and hives (KapeFiles).
  2. Parse XML, .job and TaskCache together, and correlate each XML file with its TaskCache entry by task path.
  3. Check integrity: tasks only in the registry, only on disk, missing SD, hash mismatches, and whether the hive was dirty when copied.
  4. Normalise time: infer or set the UTC offset for zoneless XML times; keep registry FILETIMEs in UTC.
  5. Triage with the suspicious-attribute list above, then corroborate with process execution evidence (Prefetch, Amcache) and event logs.

The Scheduled Tasks Parser does steps 2 to 4 in the browser: drop the folders, the hive or a KAPE/Velociraptor ZIP, and it correlates XML with TaskCache, checks hashes, flags hidden and registry-only tasks, and exports CSV or JSON. Nothing is uploaded. The walkthrough is in how to analyze scheduled tasks in your browser.

FAQ

Where does Windows store scheduled tasks?

In three places: an XML definition per task under C:\Windows\System32\Tasks, a registry copy under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache, and, for legacy tasks only, binary .job files in C:\Windows\Tasks.

Is the XML file or the registry the source of truth?

On Windows 8 and later the Task Scheduler service works from the TaskCache registry data; the XML files are kept in step with it. A task can survive in the registry after its XML file is deleted, so always collect and compare both.

Which event IDs record scheduled task creation?

Security 4698 (created, with the full task XML), 4699 (deleted), 4700 (enabled), 4701 (disabled) and 4702 (updated), which need the Audit Other Object Access Events policy; and TaskScheduler/Operational 106 (registered), 140 (updated), 141 (deleted), 200 (action started) and 201 (action completed).

Further reading

Related articles

A practical checklist to spot malicious scheduled tasks: user-writable paths, encoded PowerShell, LOLBins, SYSTEM principals, random names, hidden tasks and XML/registry mismatches.
What the TaskCache key in the SOFTWARE hive stores for each scheduled task: Tree Id/Index/SD, Tasks values, DynamicInfo run times, Actions and Triggers blobs, and the Hash.
Step by step: load task XML, .job files and the SOFTWARE hive into a free in-browser parser, read hidden and registry-only tasks, fix time zones and export. With a fictional case.