Solved Make Scheduled Task Accessible to Non-Admins


6ruvgr.jpg


, choose SYSTEM
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
it is possible to create the task manually, but running the script is significantly faster, and lets you avoid the hassle of going through each step manually when there's no need to do it manually. It's called Automation.

Your automation only automates this one task. This won't help with tasks i already created. I prefer a solution that works with any task. I'd rather not write a script for every task that i want to make accessible to users.

I'm good with manual task creation. It's called 'user-friendly' :-)

About letting the task run as SYSTEM instead of letting it run as an administrator. You said to keep the script as short as possible, and, SYSTEM is only 6 characters in length.

This whole line can be removed. It's 100 characters:
-Principal (New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount -RunLevel Highest) `

This is a button, in which case you'd only have to type 6 characters.

1753026452111.webp

But yeah, SYSTEM already has higher privileges than any user that is a member of the Administrators group anyway in the first place. So, there's that

In other words, you're increasing security risk by giving users more power than they need to run the task. Correct?

and the fact that the user account that belongs to the Administrators group could potentially be replaced with a different user account [that also belongs to the Administrators group] at some point in the future

Good point in favor of running task as SYSTEM!

Modifying the task's security descriptor is more elegent elegant

Unclear: both our solutions do that

The security descriptor of a registered task is in a binary blob in the registry under:

I read somewhere that you can just flip the 5th bit for non-admin access.

(and shorter, which, IIRC, 150 percent matches what you asked...).

Mine is shorter than yours (weird flex, right?).
- Yours: Characters 1766, Words 127
- Mine: Characters 475, Words 37

What's 150%?

Here's my updated script. TaskName isn't hardcoded, user enters their desired TaskName. You guys with your hardcoding.
mod-acl.bat
Batch:
<# :
  @powershell "iex (cat -Raw '%~f0')"
  @pause
  @exit /b %ERRORLEVEL%
#>

$TaskName = Read-Host "Task name:"
$Scheduler = New-Object -ComObject "Schedule.Service"
$Scheduler.Connect()
$Task = $Scheduler.GetFolder("\").GetTask($TaskName)
$SecurityDescriptor = $Task.GetSecurityDescriptor(0xF)
if ($SecurityDescriptor -notmatch 'A;;0x1200a9;;;AU') {
    $NewSecurityDescriptor = $SecurityDescriptor + '(A;;GRGX;;;AU)'
    $Task.SetSecurityDescriptor($NewSecurityDescriptor, 0)
}

Exit 42

Embedding PS script inside a batch file:
 
Last edited:

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
New version.
- Enforces administrative execution. Detects if run as admin. Handles cancel.
- Handles task not found, task already elevated, and task successfully elevated.

elevate-task-acl.bat
Powershell:
<# :
  @echo off
  net file 1>NUL 2>NUL || powershell Start-Process -FilePath cmd.exe -ArgumentList """/c pushd %~dp0 && %~s0 %*""" -Verb RunAs 2>$null
  net file 1>NUL 2>NUL || exit

  powershell "iex (cat -Raw '%~f0')"
  pause
  exit /b %ERRORLEVEL%
#>

$TaskName = Read-Host "Task name"
$Scheduler = New-Object -ComObject "Schedule.Service"
$Scheduler.Connect()
$ErrorActionPreference = 'SilentlyContinue'
$Task = $Scheduler.GetFolder("\").GetTask($TaskName)

if ($Task -eq $null) {
    Write-Host "Task not found."
    Exit 42
    }

$SecurityDescriptor = $Task.GetSecurityDescriptor(0xF)
if ($SecurityDescriptor -notmatch 'A;;0x1200a9;;;AU') {
    $NewSecurityDescriptor = $SecurityDescriptor + '(A;;GRGX;;;AU)'
    $Task.SetSecurityDescriptor($NewSecurityDescriptor, 0)
    Write-Host "Task ACL updated."
    }
else {Write-Host "Task ACL was already updated."}

Exit 42
 

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
ButtonControlFanatics.ps1
Powershell:
$s = New-Object -ComObject Schedule.Service
$s.Connect()
$a = 'GR','GX','GW','GA','RC','WD','WO','SD'
[Int32[]]$b = 0x20000000, 0x10000000, 0x40000000, 0x02000000, 0x00020000, 0x00040000, 0x00080000, 0x00010000
(Get-Content -Path 'Z:\TaskLists\MyTaskList.txt' | ForEach-Object {
    $t = $null
    $l = ''
    try {
        $t = $s.GetFolder("\").GetTask($_)
        if($t -and $t.Name -eq $_){
            $o = $t.GetSecurityDescriptor(0xF)
            $d = $o
            $n = 0
            $m = [regex]::Matches($d, '\(A;;([A-Z]+);;;AU\)')
            $m | ForEach-Object {
                $r = $_.Groups[1].Value
                for($i = 0; $i -lt 8; $i++){ if($r -like "*$($a[$i])*"){ $n = $n -bor $b[$i] } }
                $d = $d -replace [regex]::Escape($_.Value), ''
            }
            $m = [regex]::Matches($d, '\(A;;(0x[0-9a-fA-F]+);;;AU\)')
            $m | ForEach-Object {
                $r = [int32]$_.Groups[1].Value
                $n = $n -bor $r
                $d = $d -replace [regex]::Escape($_.Value), ''
            }
            $u = $n
            $n = $n -bor $b[1]
            $u = $u -ne $n
            if(($n -band 0x8DF0FFFF) -eq 0){
                $r = ''
                $n = -bnot $n
                for($i = 0; $i -lt 8; $i++){ if(($n -band $b[$i]) -eq 0){ $r += $a[$i] } }
            } else {
                $r = '0x{0:X8}' -f $n
            }
            $d += "(A;;$r;;;AU)"
            $t.SetSecurityDescriptor($d, 0)
            if($u){ $l = "updated and harmonized." } else { if($d -eq $o){ $l = "was already updated and harmonized." } else { $l = "harmonized." } }
        } else {
            $l = "not found."
        }
    }
    catch {
        $l = 'error.'
    }
    [PSCustomObject]@{ 'Task' = $_; 'Message' = $l }
} | Out-String -Width 4096).TrimEnd() | Format-Table -AutoSize
Write-Host "`nNo ACLs were harmed during the execution of this rights® harmonizer™."
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
@hdmi Your script sets the security descriptor for tasks that match certain patterns. What patterns? What is your code doing?
 

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
It reads the Task names from a text file to "update" and/or "harmonize" the ACL of each as needed. (That is, if the Task exists.) The "update" part means that the Generic Execute (GX) flag will be set. It is what permits standard users to start the Task on demand. Please note, the Generic Read (GR) flag will not be modified by this script. So, if the GR flag was not already set, standard users will not be able to read, or view the Task. (They don't need to be able to view it anyway, as they only need to be able to start it on demand.)

The "harmonize" part is not an official term or anything like that. lol It just means that the Allow (A) ACE(s) for Authenticated Users (AU) in the Task's DACL is/are transformed to a single ACE that, if possible, will be written in the more human-readable format, in which case the two-letter symbolic descriptors [that make it more human-readable] will be written in the conventional order. If not all of the flags that are set can be mapped to symbolic descriptors, it means that the ACE can only be formatted with the hexadecimal string value instead of the more human-readable symbolic descriptor(s) string value. (For a RegisteredTask object's security descriptor, there are 8 symbolic descriptors—each defined in the script.)

For this, all of the flags that were already set in any Allow ACEs [found in the DACL, and that apply to Authenticated Users] are accumulated into a single, 32-bit bitmask ($n). Additionally, each of these ACE strings is removed from the security descriptor ($d), as they will later be replaced with a single, new ACE string like I said. Next, the script checks if the Generic Execute (GX) flag was already set, and stores the result of the check in $u. (If so, it will let you know that in the message output.) Then, it sets the GX flag in $n, and it uses $n to generate the new ACE string to append to the security descriptor.

In short, the script not only appends the new Allow ACE for Autherticated Users, but also cleans up any already existing Allow ACEs for Authenticated Users such a way that no other rights besides Generic Execute will be modified by it—and does so with minimalistic verbosity output.
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
It reads the Task names from a text file to "update" and/or "harmonize" the ACL of each as needed. (
What text file?
 

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
Z:\TaskLists\MyTaskList.txt
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
For reasons that should be completely obvious, MyTaskList.txt is the name of a text file with a task name on each line, and that you should be able to create with Notepad or similar. You can give the file a different name and/or store it in a different path if that's what you prefer, and if you do, remember to also adjust the path in the script. Alternatively, you could always decide to make the script ask you to specify the path, e.g., by changing the line:
(Get-Content -Path 'Z:\TaskLists\MyTaskList.txt' | ForEach-Object {
..to this:
(Get-Content -Path (Read-Host "Filepath") | ForEach-Object {
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
As a relative task and PowerShell beginner, nothing is obvious to me.

So the text file would be created manually by the admin as a way to apply the ACL mod to multiple tasks, correct? That's the answer I was looking for.

Interesting! Is there a common professional need for that functionality? If not then typing just one task as my script does seems sufficient.

If admins need to do this often, then requiring them to generate a text file seems less than convenient. I'd rather the script scan load a power shell menu with all existing tasks and allow the admin to select the ones they want to mod.
 

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
I didn't think that you need to know any PowerShell to be able to guess that MyTaskList.txt is just a list of task names in a text file, but anyway. If you only need to update one task, you could always decide to change the line to this:
(ForEach-Object -InputObject (Read-Host "Task name") {

I suppose that whether you need the "harmonize" part as a professional greatly depends on how much sloppiness can be tolerated by whoever hired you for the assignment in question. Writing clean script code is one thing. Ensuring that it also produces clean results is another thing.

If you want to see a complete list with the names of all tasks that exist in the root location (\) such a way that lets you multiselect the names you want, you can change the line to this:
((Get-ScheduledTask | Where-Object { $_.TaskPath -eq "\" } | Select-Object TaskName | Out-GridView -OutputMode Multiple).TaskName | ForEach-Object {

Just in case you don't already know how to multiselect rows, the idea is to use modifier keys like Ctrl (to add or remove individual items from the selection) and Shift (to select a range of items).
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
If you only need to update one task, you could always decide to change the line to this:
(ForEach-Object -InputObject (Read-Host "Task name") {
If that's a for-each on a single object, i would call that sloppy code.

I suppose that whether you need the "harmonize" part as a professional greatly depends on how much sloppiness can be tolerated by whoever hired you for the assignment
What assignment?
If you want to see a complete list with the names of all tasks that exist in the root location (\) such a way that lets you multiselect the names you want, you can change the line to this:
((Get-ScheduledTask | Where-Object { $_.TaskPath -eq "\" } | Select-Object TaskName | Out-GridView -OutputMode Multiple).TaskName | ForEach-Object {
Great! I will use this in the future.
 

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude
@hdmi
$_.TaskPath -eq "\" }
Why is it important to use root? Why not just use path to tasks folder?

Each of the tasks in the list gets the same security setting, and t gets applied to each them, one at a time, correct?

I appreciate meaningful variable names. 😄
 
Last edited:

My Computer

System One

  • OS
    Windows 11
    Computer type
    Laptop
    Manufacturer/Model
    Dell Latitude

Latest Support Threads

Back
Top Bottom