Active Directory中拒绝域账户servicePrincipalName写入权限的代码报错求助
我最近在尝试禁止某个域账户修改自己的servicePrincipalName属性时踩了坑,写的PowerShell代码一直报错,完全搞不懂System.DirectoryServices.ActiveDirectoryAccessRule的用法哪里出问题了,有没有大佬能帮忙分析下?
我写的代码如下:
Import-Module activedirectory $Username = "test_user" $SPNProperty = "servicePrincipalName" # Get the security descriptor for the user object $SD = (Get-ADUser -Identity $Username -Properties nTSecurityDescriptor).nTSecurityDescriptor # Get the GUID of the servicePrincipalName attribute $SPNSchemaObj = Get-ADObject -SearchBase ((Get-ADRootDSE).schemaNamingContext) -Filter { LDAPDisplayName -eq $SPNProperty } -Properties schemaIDGUID $SPNSchemaID = $SPNSchemaObj.schemaIDGUI # 这里有拼写错误 # Create a new access rule to deny the "Write Property" permission for the servicePrincipalName attribute $AccessRule = (New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $Username, "WriteProperty", "Deny",$SPNSchemaID) # Add the new access rule to the security descriptor $SD.DiscretionaryAcl.AddAccessRule($AccessRule) # Set the modified security descriptor on the user object Set-ADUser -Identity $Username -Replace @{nTSecurityDescriptor = $SD}
运行后弹出了两个错误:
New-Object : Cannot find an overload for "ActiveDirectoryAccessRule" and the argument count: "6".
At line:10 char:16
- ... cessRule = (New-Object System.DirectoryServices.ActiveDirectoryAccess ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~- CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
- FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At line:14 char:1
- $SD.DiscretionaryAcl.AddAccessRule($AccessRule)
- CategoryInfo : InvalidOperation: (:) [], RuntimeException
- FullyQualifiedErrorId : InvokeMethodOnNull
问题分析与修正方案
我帮你梳理下代码里的两个关键问题:
属性拼写错误导致变量为Null
代码里$SPNSchemaID = $SPNSchemaObj.schemaIDGUI这一行写错了属性名,正确的属性应该是schemaIDGUID(少写了一个D),这会导致$SPNSchemaID的值为Null,后续调用AddAccessRule时自然会抛出“无法对Null值表达式调用方法”的错误。ActiveDirectoryAccessRule构造函数参数错误
你直接传入字符串类型的参数,但ActiveDirectoryAccessRule的构造函数需要的是特定类型的参数,而不是字符串:$Username需要转换为IdentityReference类型(比如NTAccount对象)"WriteProperty"应该用枚举值[System.DirectoryServices.ActiveDirectoryRights]::WriteProperty"Deny"应该用枚举值[System.Security.AccessControl.AccessControlType]::Deny
修正后的代码
Import-Module activedirectory $Username = "test_user" $SPNProperty = "servicePrincipalName" # 获取用户对象的安全描述符 $SD = (Get-ADUser -Identity $Username -Properties nTSecurityDescriptor).nTSecurityDescriptor # 获取servicePrincipalName属性的schemaIDGUID $SPNSchemaObj = Get-ADObject -SearchBase ((Get-ADRootDSE).schemaNamingContext) -Filter { LDAPDisplayName -eq $SPNProperty } -Properties schemaIDGUID $SPNSchemaID = $SPNSchemaObj.schemaIDGUID # 修正拼写错误 # 将用户名转换为IdentityReference对象 $identity = [System.Security.Principal.NTAccount]$Username # 定义权限和访问控制类型 $adRights = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty $accessType = [System.Security.AccessControl.AccessControlType]::Deny # 创建正确的访问规则 $AccessRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $identity, $adRights, $accessType, $SPNSchemaID # 添加访问规则到安全描述符 $SD.DiscretionaryAcl.AddAccessRule($AccessRule) # 应用修改后的安全描述符 Set-ADUser -Identity $Username -Replace @{nTSecurityDescriptor = $SD}
另外还要注意,执行这段代码需要有足够的AD权限(比如修改用户权限的权限),否则可能会出现权限不足的错误。
备注:内容来源于stack exchange,提问作者Rauf Asadov




