Active-Directory

為什麼我可以使用 Active Directory 使用者和電腦將 ACE 添加到 ACL,但不能使用 PowerShell?

  • November 9, 2016

我在 AD 中有一個名為 SQL 的 OU。我已將 OU 的完全控制權委託給名為 sqladmin 的使用者。

如果我以 sqladmin 身份登錄到成員伺服器,我可以使用 Active Directory 使用者和電腦來創建兩個不同的電腦對象,AG 和集群。我可以使用 ADUC 來設置 AG 電腦對象的安全性,以便集群電腦對象具有完全控制權。

但是,如果我嘗試使用 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$ 的 Generic All 類型,並且它與我在 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)

我認為這可能與Get-Acl引擎蓋下的工作方式有關。如果我沒記錯的話,它會檢索對象的 DACL(您想要的)和 SACL(您不想要的)。您的 sqladmin 使用者只有修改 DACL 的權限。當您使用Set-Acl修改後的對象時,它會嘗試寫入包括 SACL 在內的整個對象,即使它沒有更改。而且由於您無權訪問,因此訪問被拒絕。

這裡有一個相關的問題,它有一種解決方法來處理文件系統對象的權限。但是該GetAccessControl()方法在 AD 對像上不存在。

但是,AD 對像有自己的一組方法,您可以將其用作替代方法。其中之一是ModifyAccessRule。這是對您的程式碼進行的修改以使用它。

# 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.

引用自:https://serverfault.com/questions/814085