У меня есть подразделение в AD под названием SQL. Я делегировал полный контроль над OU пользователю sqladmin.
Если я вхожу на рядовой сервер как sqladmin, я могу использовать «Пользователи и компьютеры Active Directory» для создания двух разных компьютерных объектов: AG и Cluster. Я могу использовать ADUC, чтобы установить безопасность на компьютерном объекте AG, чтобы компьютерный объект «Кластер» имел полный контроль.
Однако, если я попытаюсь сделать это с помощью PowerShell, отключив текущий ACL от AG и добавив ACE, я получу ошибку «Доступ запрещен» при попытке установить ACL для объекта AG Computer.
Вот мой код
$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. Однако я могу выполнить эту задачу с помощью sqladmin, используя графический интерфейс.
Я также могу подтвердить, что если я использую графический интерфейс, созданный ACE имеет тип Generic All для CLUSTER $ и соответствует тому, что я пытаюсь сделать в PowerShell. Мне нужно обновить ACL с помощью учетной записи пользователя, которой был делегирован доступ к OU с помощью PowerShell.
Вот ошибка, которую я вижу, когда пытаюсь сделать это с помощью 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.