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:

  1. 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).
  2. 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.
  3. 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:

image

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 $task

Note 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 owner

If 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

  1. Run a scheduled task under the Local Service or Network Service accounts. Set permissions for the task sid.
  2. You can run a scheduled task under a gMSA, but then it will not have a task sid.
  3. 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.

Next: Scheduled Task to Start Privileged Application