允许非管理员用户在 Windows Server 2016 中运行计划任务

允许非管理员用户在 Windows Server 2016 中运行计划任务

在以前版本的 Windows 中,我们可以通过授予对 WINDOWS\SYSTEM32\Tasks 中的文件的“读取+执行”权限来允许用户执行计划任务。

这在 Windows 2016 中不再有效。我尝试授予每个人对 MyTask 文件的完全访问权限。但我仍然得到:

schtasks.exe /Run /TN "MyTask"
ERROR: Access is denied.

有人知道如何在 Windows 2016 中实现这一点吗?

编辑:我使用 ntrights 向帐户授予了 SeBatchLogonRight,但没有什么区别。

答案1

此线程中有一个 powershell 脚本,它将授予经过身份验证的用户对任务的读取和执行权限:

https://social.technet.microsoft.com/Forums/windows/en-US/6b9b7ac3-41cd-419e-ac25-c15c45766c8e/scheduled-task-that-any-user-can-run?forum=win10itprogeneral

答案2

Magic Code 仍然需要 PSExec 将权限提升到“系统帐户”,因为否则无法修改注册表项:

.\psexec.exe -s -i powershell.exe

然后我们需要获取适用对象的 Account Sid

get-aduser USERNAME | select sid   #Plenty of other ways to accomplish this

# Then we Get SDDL from existing task, to ensure that we maintain the proper owner and creator ID’s
$PathToTask = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\TASKYOUWISHTOALLOWTOBETRIGGERED"
$SDBin =  ( (get-itemProperty $PathToTask).SD )
# the $existingSDDL is the string we will actually be modifying (which is technically of the parent object that we are going to apply the new value to)
$existingSDDL = ([wmiclass]"Win32_SecurityDescriptorHelper").BinarySDToSDDL($SDBin).SDDL
# The result returned below is the interpretation of it in English
$secEnglish = ConvertFrom-SddlString ([wmiclass]"Win32_SecurityDescriptorHelper").BinarySDToSDDL($SDBin).SDDL
$sec.DiscretionaryAcl

# The $existingSDDL will look something akin to the $p1 value
$p1 = 'O:BAG:DUD:(A;ID;0x1f019f;;;BA)(A;ID;0x1f019f;;;SY)(A;ID;FA;;;BA)(A;;FR;;;S-1-5-21-0000000000-111111111-2222222222-3333)'
# We then need to add the appropriate DACL for the account/SID we want to grant permissions to and the FA (File Full Access) permission to the string
$p2 = 'O:BAG:DUD:(A;ID;0x1f019f;;;BA)(A;ID;0x1f019f;;;SY)(A;ID;FA;;;BA)(A;;FR;;;S-1-5-21-0000000000-111111111-2222222222-3333)(A;;FR;;;S-1-5-21-0000000000-111111111-2222222222-9999)'

# We then need to convert the DACL into a binary Value to be applied to the SD (REG_BINARY) ****Value****, not the security of the object but the actual value of the SD Key
$p2BinVal = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($p2).BinarySD

#一旦我们有了正确的二进制值,我们就可以更新键 Set-ItemProperty -Path $PathToTask -Name SD -Value (byte[]) 的值

#如果密钥在此过程中被错误地设置为不同的数据类型,您可以将其删除并重新创建 remove-itemproperty -path $PathToTask -name "SD" New-ItemProperty -Path $PathToTask -Name SD -PropertyType Binary -Value ([byte[]]$p2BinVal)

DACL/SACL 注释:标头 D:= DACL S:= SACL G:= 主要组 O:= 所有者 DACL 和 SACL 是括在()中的 ACE 的组合 6 个字段 ACE 类型(允许/拒绝/审核)、ACE 标志(继承和审核设置)、权限(增量权限列表)、对象类型 (GUID)、继承对象类型 (GUID) 和受托人 (SID) https://itconnect.uw.edu/wares/msinf/other-help/understanding-sddl-syntax/

答案3

Vladimir 提供的链接似乎是解决方案。由于指向 Microsoft 的链接最终总会消失,因此我在此处复制了完整的解决方案。powershell 脚本来自 social.technet.microsoft.com 上的用户 MotoX80。

MotoX80写道:

我之前调查过这个问题,但无法像您发现的那样使文件权限更改正常工作。

这次我挖得更深了一点,发现了 SD 注册表值。请参阅代码中的注释。我构建了一个 Powershell 脚本,将其命名为 UnlockScheduledTask.ps1。这在 Win10Pro 上对我有用。只需创建一个任务,然后解锁它。

尝试一下,看看它是否适合你。

<#

.SYNOPSIS
This Powershell script updates the security descriptor for scheduled tasks so that any user can run the task. 

Version 1.0 of this script only displays tasks in the root folder. I want to make sure that works first. 

.DESCRIPTION
Earlier versions of Windows apparently used file permissions on C:\Windows\System32\Tasks files to manage security.
Windows now uses the SD value on tasks under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree to accomplish that. 

By default, this script will display the SDDL on all tasks. If a taskname is passed as a parameter, this script will grant Authenticated users read and execute permissions to the task. 

This script accepts 1 parameters.
-taskname   The name of a scheduled task. 

.EXAMPLE
./UnlockScheduledTask.ps1 
./UnlockScheduledTask.ps1 -taskname "My task"  

.NOTES
Author: Dave K. aka MotoX80 on the MS Technet forums. (I do not profess to be an expert in anything. I do claim to be dangerous with everything.)



.LINK
http://www.google.com

#>

param (
    [string]$taskname = ""   
 )

 'UnlockScheduledTask.ps1  Version 1.0'
 if ($taskname -eq '') {
    ''
    'No task name specified.'
    'SDDL for all tasks will be displayed.'
    ''
 } else {
    $batFile = "$env:TEMP\Set-A-Task-Free.bat"           # if you don't like my names, you can change them here. 
    $updateTaskName = 'Set-A-Task-Free'
    ''
    "SDDL for $taskname will be updated via $batfile"
    ''
 }
 $wmisdh = new-object system.management.ManagementClass Win32_SecurityDescriptorHelper 
 $subkeys = Get-childitem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree"
 foreach ($key in $subkeys) {
    if ($taskname -eq '') {              # if blank, show SDDL for all tasks 
        ''
        $key.PSChildName
        $task = Get-ItemProperty $($key.name).replace("HKEY_LOCAL_MACHINE","HKLM:")
        $sddl = $wmisdh.BinarySDToSDDL( $task.SD ) 
        $sddl['SDDL']        
    
    } else {
        if ($key.PSChildName -eq $taskname) {
            ""
            $key.PSChildName
            $task = Get-ItemProperty $($key.name).replace("HKEY_LOCAL_MACHINE","HKLM:")
            $sddl = $wmisdh.BinarySDToSDDL( $task.SD ) 
            $sddl['SDDL']
            ''
            'New SDDL'
            $newSD = $sddl['SDDL'] +  '(A;ID;0x1301bf;;;AU)'          # add authenticated users read and execute
            $newSD                                                    # Note: cacls /s will display the SDDL for a file. 
            $newBin = $wmisdh.SDDLToBinarySD( $newsd )
            [string]$newBinStr =  $([System.BitConverter]::ToString($newBin['BinarySD'])).replace('-','') 
            
            # Administrators only have read permissions to the registry vlaue that needs to be updated.
            # We will create a bat file with a reg.exe command to set the new SD.
            # The bat file will be invoked by a scheduled task that runs as the system account.
            # The bat file can also be reused if the task is deployed to other machines. 
            ''
            "reg add ""HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{0}"" /f /v SD /t REG_BINARY /d {1}" -f $key.PSChildName, $newBinStr
            "reg add ""HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{0}"" /f /v SD /t REG_BINARY /d {1}" -f $key.PSChildName, $newBinStr  | out-file -Encoding ascii $batfile  
            ''

            SCHTASKS /Create /f /tn "$updateTaskName" /sc onstart  /tr "cmd.exe /c $batfile" /ru system 
            SCHTASKS /run /tn "$updateTaskName"
            $count = 0
            while ($count -lt 5) {
                start-sleep 5
                $count++
                $(Get-ScheduledTask -TaskName $updateTaskName).State
                if ($(Get-ScheduledTask -TaskName $updateTaskName).State -eq 'Ready') {
                    $count = 99            # it's ok to procees
                }
            }
            if ($count -ne 99) {
                "Error! The $updateTaskName task is still running. "
                'It should have ended by now.'
                'Please investigate.'
                return
            }
            SCHTASKS /delete /f /tn "$updateTaskName"
            ''
            'Security has been updated. Test it.'
        }
    }      
 }

答案4

允许非管理员用户在 Windows Server 2016 中运行计划任务及以上,您可以使用以下 Powershell 脚本。

此脚本修改特定命名的计划任务的 ACL。这些 ACL 存储在注册表中。此脚本授予已认证用户查看和执行不是由他们创建的计划任务的能力。

在 Powershell 中运行以下代码。 以管理员身份运行获得正确的权限才能成功完成此操作。

在运行代码之前,更改$任务路径$任务名称以匹配您自己的计划任务。

####################################

#IMPORTANT:  Run Powershell As Administrator

####################################

$TaskName = "(the name of the Scheduled Task you want to run)"
$TaskPath = "\" #Scheduled Tasks at the base level use this path. If you have folders in your Task Scheduler, just add in the folder path here after the backslash.
$Scheduler = New-Object -ComObject "Schedule.Service"
$Scheduler.Connect()
$GetTask = $Scheduler.GetFolder($TaskPath).GetTask($TaskName)
$GetSecurityDescriptor = $GetTask.GetSecurityDescriptor(0xF)
if ($GetSecurityDescriptor -notmatch 'A;;0x1200a9;;;AU') {
    $GetSecurityDescriptor = $GetSecurityDescriptor + '(A;;GRGX;;;AU)'
    $GetTask.SetSecurityDescriptor($GetSecurityDescriptor, 0)
}

注意:在创建这个答案时,我修改了此处的脚本: https://www.osdeploy.com/blog/2021/scheduled-tasks/task-permissions

相关内容