为什么我可以使用 Active Directory 用户和计算机将 ACE 添加到 ACL,但不能使用 PowerShell?

为什么我可以使用 Active Directory 用户和计算机将 ACE 添加到 ACL,但不能使用 PowerShell?

我在 AD 中有一个名为 SQL 的 OU。我已将该 OU 的完全控制权委托给名为 sqladmin 的用户。

如果我以 sqladmin 身份登录成员服务器,我可以使用 Active Directory 用户和计算机创建两个不同的计算机对象,AG 和 Cluster。我可以使用 ADUC 设置 AG 计算机对象的安全性,以便 Cluster 计算机对象拥有完全控制权。

但是,如果我尝试使用 PowerShell 通过从 AG 中获取当前 ACL 并添加 ACE 来执行此操作,则当我尝试在 AG 计算机对象上设置 ACL 时会出现访问被拒绝错误。

这是我的代码

$AG = Get-ADComputer AG
$cluster = Get-ADComputer cluster

$AGDistinguishedName = $AG.DistinguishedName  # input AD computer distinguishedname
$AGacl = Get-Acl "AD:\$AGDistinguishedName"

$SID = [System.Security.Principal.SecurityIdentifier] $cluster.SID

$identity = [System.Security.Principal.IdentityReference] $SID
$adRights = [System.DirectoryServices.ActiveDirectoryRights] "GenericAll"
$type = [System.Security.AccessControl.AccessControlType] "Allow"
$inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance] "None"

$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $identity,$adRights,$type,$inheritanceType

$AGacl.AddAccessRule($ace) 

Set-Acl -path "AD:\$AGDistinguishedName" -AclObject $AGacl

但是,如果我以域管理员身份登录并运行代码,它就可以正常工作。只有当我以 sqladmin 用户身份登录时,代码才会失败。但是,我可以使用 GUI 使用 sqladmin 执行任务。

我还可以确认,如果我使用 GUI,则创建的 ACE 具有 CLUSTER$ 的通用全部类型,并且它与我在 PowerShell 中尝试执行的操作相匹配。我需要能够使用已使用 PowerShell 委派访问 OU 的用户帐户来更新 ACL。

这是我尝试使用 PowerShell 执行此操作时看到的错误。

System.UnauthorizedAccessException: Access is denied ---> 
                        System.ServiceModel.FaultException: The operation failed due to insufficient access rights.
                           --- End of inner exception stack trace ---
                           at 
                        Microsoft.ActiveDirectory.Management.AdwsConnection.ThrowExceptionForExtendedError(String 
                        extendedErrorMessage, Exception innerException)
                           at Microsoft.ActiveDirectory.Management.AdwsConnection.ThrowExceptionForErrorCode(String 
                        message, String errorCode, String extendedErrorMessage, Exception innerException)
                           at 
                        Microsoft.ActiveDirectory.Management.AdwsConnection.ThrowExceptionForFaultDetail(FaultDetail 
                        faultDetail, FaultException faultException)
                           at Microsoft.ActiveDirectory.Management.AdwsConnection.ThrowException(AdwsFault 
                        adwsFault, FaultException faultException)
                           at Microsoft.ActiveDirectory.Management.AdwsConnection.Modify(ADModifyRequest request)
                           at Microsoft.ActiveDirectory.Management.ADWebServiceStoreAccess.Microsoft.ActiveDirectory.
                        Management.IADSyncOperations.Modify(ADSessionHandle handle, ADModifyRequest request)
                           at Microsoft.ActiveDirectory.Management.ADActiveObject.Update()
                           at Microsoft.ActiveDirectory.Management.Provider.ADProvider.SetSecurityDescriptor(String 
                        path, ObjectSecurity securityDescriptor)

答案1

Get-Acl我认为这可能与底层工作原理有关。如果我没记错的话,它会检索对象的 DACL(您想要的)和 SACL(您不想要的)。您的 sqladmin 用户只有修改 DACL 的权限。当您Set-Acl使用修改后的对象时,它会尝试写入整个对象(包括 SACL),即使它没有更改。由于您没有访问权限,因此您的访问被拒绝。

有一个相关问题这里该方法提供了一种处理文件系统对象权限的解决方法。但该GetAccessControl()方法不适用于 AD 对象。

但是,AD 对象有自己的一组方法可以作为替代方法使用。其中之一是修改访问规则。这是对您的代码进行修改以便使用它。

# grab the data you need from the AD objects
$AG = Get-ADComputer AG
$AGDN = $AG.DistinguishedName  # input AD computer distinguishedname
$cluster = Get-ADComputer cluster
$SID = [System.Security.Principal.SecurityIdentifier] $cluster.SID

# create the ACE you want to add
$identity = [System.Security.Principal.IdentityReference] $SID
$adRights = [System.DirectoryServices.ActiveDirectoryRights] "GenericAll"
$type = [System.Security.AccessControl.AccessControlType] "Allow"
$inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance] "None"
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $identity,$adRights,$type,$inheritanceType

# get an ADSI reference to the AD object we're going to tweak
$AGADSI = [adsi]"LDAP://$AGDN"

# we need an existing boolean output variable for the function
$modified = $false

# call the function and commit the changes
$AGADSI.PSBase.ObjectSecurity.ModifyAccessRule([System.Security.AccessControl.AccessControlModification]::Add,$ace,[ref]$modified)
$AGADSI.PSBase.CommitChanges()

# you could/should check the value of $modified to make sure it's True before doing the
# commit. But hypothetically the only thing that would screw it up is if you botched the
# ACE creation.

相关内容