Windows Unprivileged - The Secret Lives of Scheduled Tasks
Note that absolutely none of this is authoritative or directly based on relevant documentation. It’s mostly what I found and figured out and guessed and (in some cases) made up. Some of it may be wrong or dangerous or lead to disaster or confusion. I am not taking responsibility here for anything. Read and act on it at your own peril!
The Windows Task Scheduler is a horrible tool.
Not only does it often appear to be highly unreliable (it is not, it’s just ridiculously capricious, as in, a small misconfiguration will cause maximum damage), but it is also pretty much designed to be configured for permissions (hence small misconfigurations happen a lot more often than they should).
The first three things you have to know about Windows Task Scheduler permissions are these:
- Scheduled task permissions are stored as byte arrays in the system registry, in a key and subkeys that are not writable even to Administrators (let alone the scheduled task owners).
- Scheduled task permissions do not inherit, that is a scheduled task in a scheduled task folder does not inherit the permissions of the scheduled task folder and the scheduled task folder does not inherit permissions from its parent folder either.
- The permission getting and setting functionality of the scheduled task cmdlets does not work. And that’s it.
Note that in Windows any object created by a user will then be owned by the user. An owner can always change the permissions on the object. That is what the “discretionary” in “discretionary access control” means. But for scheduled tasks this is not true. While a scheduled task created by user benoit will be “owned” by user benoit, user benoit cannot change permissions on the scheduled task because of point #1 above.
Also note that in Windows any object created by a member of the Administrators group will be owned by the Administrators group. But even a member of the Administrators group cannot change scheduled task permissions. If a member of the Administrators group created a scheduled task, no restricted user will be able to see the task.
Task permissions are stored beneath this registry key:
HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\> dir
Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree
Name Property
---- --------
Microsoft SD : {1, 0, 20, 156...}
MicrosoftEdgeUpdateTaskMachine SD : {1, 0, 4, 128...}
Core{AF97B5B7-628F-4A2A-A93E-C Id : {2ACF5743-7CF9-4E2E-8AD5-40FCDDCFA72A}
37F4C6FBFFA} Index : 2
MicrosoftEdgeUpdateTaskMachine SD : {1, 0, 4, 128...}
UA{0675DC18-57C0-41F8-BB75-FD8 Id : {25E74989-7221-4208-A380-26330BE002C9}
2D1690C93} Index : 3
TestFolder SD : {1, 0, 4, 140...}
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\>Permissions for each task or task folder are stored in the Property “SD” of each corresponding key as byte arrays.
Using the WMI helper class Win32_SecurityDescriptorHelper these byte arrays can be translated into security descriptor objects or security descriptor definition language strings.
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\> $sd=(Get-ItemProperty TestFolder).SD
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\> $helper=[wmiclass]"Win32_SecurityDescriptorHelper"
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\> $sddl=$helper.BinarySDToSDDL($sd).SDDL
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\> $sddl
O:BAG:S-1-5-21-344341352-2539047333-2300305637-513D:AI(A;CI;FA;;;BA)(A;OIIO;0x1f019f;;;BA)(A;CI;FA;;;SY)(A;OIIO;0x1f019f;;;SY)(A;CI;FW;;;AU)(A;CI;FW;;;NS)(A;CI;FW;;;LS)(A;OICIIO;FA;;;CO)
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\>The sddl string shows is the following:
| O:BA | The owner is this task (actually a folder) is BUILTIN\Administrators |
| G:S-1-5-21-344341352-2539047333-2300305637-513 | This is the group owner of the task, it does not concern us |
| D:AI | This is the start of the discretionary acccess control list for the folder, which is allegedly “AUTO_INHERITED” |
| (A;CI;FA;;;BA) | This is an “Allow” access control element, which gives FA full access to BA BUILTIN\Administrators |
| (A;OIIO;0x1f019f;;;BA) | More rights for BA |
| (A;CI;FA;;;SY) | Full access for SY, the system account |
| (A;OIIO;0x1f019f;;;SY) | More rights for system account |
| (A;CI;FW;;;AU) | FW file write (generic write) for AU Authenticated Users |
| (A;CI;FW;;;NS) | Same for NS Network Service |
| (A;CI;FW;;;LS) | Same for LS Local Service |
| (A;OICIIO;FA;;;CO) | And full access for CO Creator Owner (the owner of the object) |
In TuskForce this can be seen better:

You can download TuskForce as part of the Elephant permissions editor here: Introduction
In order to change any of those permissions you need to be either running as LocalSystem or allow yourself (or better a group you are in) full access to the respective registry key hierarchy.
You can then use this PowerShell script to grant full access to a folder or task to a specific user or group: scheduled tasks permissions script
I recommend creating a scheduled task running as LocalSystem that will regularly run this script against certain task folders to reset the permissions.
PS C:\> (Get-ScheduledTask "SchedTaskPermissions TestFolder").Actions
Id :
Arguments : C:\SchedTaskPermissions.ps1 TestFolder benoit -Recurse -NoConfirm
Execute : powershell.exe
WorkingDirectory : C:\
PSComputerName :
PS C:\>You can set it up in the task scheduler GUI. Just make sure it runs as LocalSystem and create one for each task folder that must be accessible by a specific group or user.
Note that you probably want folder names to be more specific and you want a group for each folder rather than user benoit. Also don’t keep the permissions script on C:\.
Such a scheduled task will keep tasks in specific folders accessible to specific groups. You can schedule the task to run daily our hourly and/or make it available to all users to run when they need to fix permissions on their scheduled tasks.
Annex: How to create a scheduled task using PowerShell
PS C:\> $action=New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c cls"
PS C:\> $task=New-ScheduledTask -Action $action -Settings (New-ScheduledTaskSettingsSet)
PS C:\> Register-ScheduledTask -TaskName "BenoitTestTask" -User "benoit" -Password "Password1" -InputObject $task
TaskPath TaskName State
-------- -------- -----
\ BenoitTestTask Ready
PS C:\> Get-ScheduledTask BenoitTestTask
TaskPath TaskName State
-------- -------- -----
\ BenoitTestTask Ready
PS C:\> Start-ScheduledTask BenoitTestTask
PS C:\> Unregister-ScheduledTask BenoitTestTask
Confirm
Are you sure you want to perform this action?
Performing operation 'Delete' on Target '\BenoitTestTask'.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
PS C:\>To create a scheduled task that runs as LocalSystem, do the following registration (as an administrator):
Register-ScheduledTask -TaskName "BenoitTestTask" -User "System" -InputObject $taskNote that you should not do that. See What Account Should One Use.
It is better to create scheduled tasks that run as Local Service or Network Service (depending on whether they need network access or not) and then grant necessary permissions to the task sid:
Consider this example:
PS C:\Test> "whoami/groups > c:\test\testtask.log" | Out-File TestTask.cmd -Encoding ascii
PS C:\Test> $action=New-ScheduledTaskAction -Execute "C:\Test\TestTask.cmd"
PS C:\Test> $task=New-ScheduledTask -Action $action -Settings (New-ScheduledTaskSettingsSet)
PS C:\Test> Register-ScheduledTask -TaskName "TestTask" -User "LocalService" -InputObject $task
TaskPath TaskName State
-------- -------- -----
\ TestTask Ready
PS C:\Test> icacls . /grant "LocalService:F"
processed file: .
Successfully processed 1 files; Failed processing 0 files
PS C:\Test> Start-ScheduledTask TestTask
PS C:\Test> Get-Content .\testtask.log
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
====================================== ================ ================================================================================================ ==================================================
Mandatory Label\System Mandatory Level Label S-1-16-16384
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT TASK\TestTask Well-known group S-1-5-87-3726386359-1781312220-494297941-3560601597-4137362352 Enabled by default, Enabled group, Group owner
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
PS C:\Test>It creates a scheduled task running under the Local Service built-in account that simply writes its group memberships into a log file. (To allow writing the file, permissions are given to Local Service to the directory.)
Note the line
NT TASK\TestTask Well-known group S-1-5-87-3726386359-1781312220-494297941-3560601597-4137362352 Enabled by default, Enabled group, Group ownerIf your scheduled task needs permissions, use the NT TASK\TestTask principal instead of the LocalService principal:
PS C:\Test> icacls . /remove LocalService
processed file: .
Successfully processed 1 files; Failed processing 0 files
PS C:\Test> icacls . /grant "NT TASK\TestTask:F"
processed file: .
Successfully processed 1 files; Failed processing 0 files
PS C:\Test> Remove-Item .\testtask.log
PS C:\Test> Start-ScheduledTask TestTask
PS C:\Test> Get-Content .\testtask.log
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
====================================== ================ ================================================================================================ ==================================================
Mandatory Label\System Mandatory Level Label S-1-16-16384
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT TASK\TestTask Well-known group S-1-5-87-3726386359-1781312220-494297941-3560601597-4137362352 Enabled by default, Enabled group, Group owner
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
PS C:\Test>Permissions for scheduled tasks, like permissions for services, should be application-specific (i.e. for the task or service), not account-specific (i.e. not for the account).
You can also use a gMSA, but this gets weird quickly:
PS C:\Test> "whoami/groups > c:\test\testtask.log" | Out-File TestTask.cmd -Encoding ascii
PS C:\Test> $action=New-ScheduledTaskAction -Execute "C:\Test\TestTask.cmd"
PS C:\Test> $principal=New-ScheduledTaskPrincipal -UserID Netneurotic\Test1$ -LogonType Password
PS C:\Test> Register-ScheduledTask -TaskName "TestTask" -Principal $principal -Action $action
TaskPath TaskName State
-------- -------- -----
\ TestTask Ready
PS C:\Test> icacls . /grant "Netneurotic\Test1`$:F"
processed file: .
Successfully processed 1 files; Failed processing 0 files
PS C:\Test> Start-ScheduledTask TestTask
PS C:\Test> Get-Content .\testtask.log
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
========================================== ================ ============================================= ==================================================
NETNEUROTIC\Domain Computers Group S-1-5-21-2748734040-3420492860-1821007455-515 Mandatory group, Enabled by default, Enabled group
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
NT SERVICE\ALL SERVICES Well-known group S-1-5-80-0 Mandatory group, Enabled by default, Enabled group
Authentication authority asserted identity Well-known group S-1-18-1 Mandatory group, Enabled by default, Enabled group
Mandatory Label\High Mandatory Level Label S-1-16-12288
PS C:\Test>The scheduled task running under the gMSA does not feature a task sid NT TASK\Whatever and hence cannot be permissioned directly. You have to set permissions for the gMSA instead.
;tldr
- Run a scheduled task under the Local Service or Network Service accounts. Set permissions for the task sid.
- You can run a scheduled task under a gMSA, but then it will not have a task sid.
- You can run a scheduled task under a user account, but then it will share the rights of that user account, so better don’t.