Skip to content

Windows Scheduled Task XML Explained, Element by Element

Read a Task Scheduler XML file like an investigator: RegistrationInfo, Triggers, Principals, Settings and Actions, and the zoneless local times in Date and StartBoundary.

Published on 6 min read

TL;DR. A task XML has five sections that matter: RegistrationInfo (who and when, as claimed), Triggers (when it fires), Principals (which account, which privileges), Settings (hidden, enabled, limits) and Actions (what runs). Two traps: Date and StartBoundary are usually local time with no offset, and Author is free text. Read the file as a set of claims and check them against TaskCache and event logs.

The format is documented in Microsoft's Task Scheduler Schema, with the namespace http://schemas.microsoft.com/windows/2004/02/mit/task. This article reads it from an investigator's point of view. Where the files live is in scheduled task locations and acquisition.

A minimal example

A task registered with schtasks on a workstation typically looks like this. It is trimmed from the fictional FIN-WKS-07 sample used throughout this site, set to UTC+02:00:

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2026-09-14T12:09:58.4413872</Date>
    <Author>FIN-WKS-07\svc_backup</Author>
    <Description>Intel graphics telemetry</Description>
    <URI>\IntelGfxTelemetry</URI>
  </RegistrationInfo>
  <Triggers>
    <BootTrigger><Enabled>true</Enabled></BootTrigger>
    <TimeTrigger>
      <Repetition><Interval>PT1H</Interval></Repetition>
      <StartBoundary>2026-09-14T12:15:00</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <Hidden>true</Hidden>
    <Enabled>true</Enabled>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\ProgramData\Intel\m64.exe</Command>
      <Arguments>-svc</Arguments>
    </Exec>
  </Actions>
</Task>

The file on disk is usually UTF-16LE with a byte order mark, even though the XML declaration is sometimes copied around as UTF-8. A parser that assumes UTF-8 will show garbage; that alone is a reason to use a tool built for the format.

RegistrationInfo: the claimed metadata

ElementWhat it saysHow far to trust it
URITask path in the library, e.g. \Microsoft\Windows\Defrag\ScheduledDefragShould match the file path and the TaskCache Tree key; a mismatch is worth noting
AuthorWho registered the taskFree text. Console and schtasks write DOMAIN\user; installers often write a vendor name; some Microsoft tasks use a resource reference like $(@%SystemRoot%\system32\...)
DateRegistration dateUsually local time, no offset (see below)
DescriptionHuman descriptionFree text; attackers copy Microsoft wording
SecurityDescriptorOptional SDDL for the taskRare in XML; the effective descriptor is TaskCache's SD value
Source, Version, DocumentationOptionalOccasionally useful for vendor attribution

Practitioner notes such as Psmths' Windows forensic artifacts point out that the Author of a remotely created task can reveal the originating account, but nothing prevents an XML import from carrying a forged author. Compare with the SubjectUserName of event 4698 or 106 when you have them.

Triggers: when it fires

The schema allows up to 48 triggers per task: BootTrigger, LogonTrigger, RegistrationTrigger, IdleTrigger, TimeTrigger, CalendarTrigger, EventTrigger and SessionStateChangeTrigger. All share Enabled, StartBoundary, EndBoundary, Repetition and ExecutionTimeLimit.

Investigative reading:

  • Boot and Logon triggers are classic persistence. A LogonTrigger without UserId fires for any user.
  • RegistrationTrigger fires once when the task is registered: a common way to run something immediately while looking like a scheduled job.
  • TimeTrigger with a short Repetition interval (for example PT5M) is a beacon-like pattern.
  • EventTrigger carries an XPath Subscription query; it can make a task fire on a specific event ID, which is easy to miss.
  • SessionStateChangeTrigger (SessionUnlock, RemoteConnect) is less common and worth a second look.

Principals: which account, which privileges

ElementValuesMeaning
UserIdAccount name or SID (S-1-5-18 is SYSTEM, S-1-5-19 LOCAL SERVICE, S-1-5-20 NETWORK SERVICE)The security context
GroupIdGroup name or SIDRuns for members of a group, e.g. S-1-5-32-545 (Users)
LogonTypeInteractiveToken, Password, S4U, InteractiveTokenOrPasswordHow the account is logged on; see S4U
RunLevelLeastPrivilege, HighestAvailableWhether an administrator token is used; see run level

A non-Microsoft task running as S-1-5-18 with HighestAvailable is the combination to sort first. LogonType Password means credentials were stored so the task can run while the user is logged off; Microsoft's guidance on event 4698 recommends alerting on it because the stored password is recoverable by an administrator.

Settings: the switches that hide or throttle

The elements to read first are Hidden, Enabled, ExecutionTimeLimit (PT0S means no limit), MultipleInstancesPolicy, StartWhenAvailable, DisallowStartIfOnBatteries, WakeToRun, RunOnlyIfNetworkAvailable and DeleteExpiredTaskAfter.

Hidden=true only hides the task in the console unless "Show Hidden Tasks" is ticked. It does not hide it from schtasks, the API or the registry. The stronger hiding techniques live in the registry, see Tarrask and hidden scheduled tasks. DeleteExpiredTaskAfter with an EndBoundary makes a task delete itself: its absence later is not evidence it never existed.

Actions: what runs

ActionContentNotes
ExecCommand, Arguments, WorkingDirectoryThe vast majority of tasks
ComHandlerClassId (CLSID), optional DataRuns a COM object, typically a DLL loaded in taskhostw.exe; see COM handler action
SendEmailServer, To, Subject...Deprecated by Microsoft; rare on modern systems
ShowMessageTitle, BodyDeprecated; rare

The Actions element has a Context attribute naming the principal. Up to 32 actions are allowed and they run in order, so read them all: a benign first action can precede a malicious second one.

For ComHandler, resolve the CLSID in the SOFTWARE hive (Classes\CLSID\{...}\InprocServer32) to find the DLL. Hijacking a CLSID that a legitimate task already uses is a quieter form of persistence than creating a new task.

Time: zoneless local values

The schema types Date, StartBoundary and EndBoundary as xs:dateTime. The scripting API documents the format YYYY-MM-DDTHH:MM:SS(+-)HH:MM with an offset (Trigger.StartBoundary). In practice, tasks created in the console or with schtasks store no offset, and the time is the machine's local time when the task was saved. Some tasks store a Z or an explicit offset; most do not.

This matters as soon as you compare with UTC sources. In Microsoft's 4698 sample, the event's TimeCreated is 2015-09-23T02:03:06Z and the XML Date is 2015-09-22T19:03:06.9258653: the same instant, seven hours apart.

Ways to recover the offset:

  1. TaskCache: DynamicInfo holds a creation FILETIME in UTC for the same task; the difference with Date is the offset, rounded to the nearest quarter hour. See TaskCache registry forensics.
  2. SYSTEM hive: TimeZoneInformation gives the configured zone; remember daylight saving applies at the date of the event, not the date of collection.
  3. Event 4698: TimeCreated in UTC against the embedded Date.

The Scheduled Tasks Parser does the first automatically: it compares XML registration dates with TaskCache FILETIMEs, proposes an offset, and lets you override it.

StartBoundary has an extra subtlety: it is when the trigger becomes active, which can be in the past (tasks created "now" often get the creation minute) or far in the future. It is not a run time. Run times come from TaskCache DynamicInfo and events 200/201.

FAQ

What time zone is the Date in a scheduled task XML?

Usually none. The schema allows an offset, but tasks created in the console or with schtasks typically store local time without any offset. Infer the offset from a UTC source, such as TaskCache FILETIMEs or event 4698's TimeCreated, before comparing with other evidence.

Does the Author field prove who created the task?

No. Author is free text written by whatever registered the task. The console and schtasks fill it with the creating account, but a script or an imported XML can put anything there. Treat it as a claim to verify against event logs.

What does Hidden=true mean?

The task is not shown in the Task Scheduler console unless the user enables Show Hidden Tasks. It is still listed by schtasks and by the API. Many Microsoft tasks are hidden, so it matters mostly for non-Microsoft tasks.

Related articles

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.
A practical checklist to spot malicious scheduled tasks: user-writable paths, encoded PowerShell, LOLBins, SYSTEM principals, random names, hidden tasks and XML/registry mismatches.
How to read legacy .job files: the MS-TSCH fixed and variable sections, triggers, the local-time last run SYSTEMTIME, and when .job files still appear on modern Windows.