我想要做的事情:我想将用户“octo”添加为“Key Admins”的成员。之后,我想将“Key Admins”添加到 AdminSDHolder,并为“Key Admins”的 msDS-KeyCredentialLink 属性设置写入和读取权限。我已经编写了一个 PowerShell 脚本来实现这一点,但在运行它时遇到了当前错误。
我正在尝试使用 PowerShell 在 Active Directory 中设置 AdminSDHolder 对象的权限。但是,在创建 System.DirectoryServices.ActiveDirectoryAccessRule 类的实例时遇到错误。这是我使用的代码:
function Set-KeyCredentialLinkPermissions {
param (
[Parameter(Mandatory = $true)]
[string] $groupName,
[Parameter(Mandatory = $true)]
[string] $userToAdd
)
# Add the user to the group
try {
Add-ADGroupMember -Identity $groupName -Members $userToAdd
Write-Output "$userToAdd was successfully added to the $groupName group."
} catch {
Write-Error "An error occurred while adding the user to the group: $_"
return
}
# Get the DistinguishedName of the AdminSDHolder object
$adminSDHolderDN = (Get-ADObject -Filter { Name -eq "AdminSDHolder" } -Properties DistinguishedName).DistinguishedName
try {
# Connect to the AdminSDHolder object
$adsi = [ADSI]"LDAP://$adminSDHolderDN"
# Get the ObjectSID of the group
$groupSID = (Get-ADGroup -Identity $groupName -Properties ObjectSID).ObjectSID
# Convert the SID to string format
$identityReference = $groupSID.Value
# GUID for msDS-KeyCredentialLink attribute
$guidKeyCredentialLink = "2f68b1d6-f5ae-4cb6-b34f-8108b3409d6b" # msDS-KeyCredentialLink GUID
# Get the current ACL
$acl = $adsi.ObjectSecurity
# Optionally clear existing rules (to leave only msDS-KeyCredentialLink permissions)
$acl.Access | Where-Object { $_.IdentityReference -eq $identityReference } | ForEach-Object {
$acl.RemoveAccessRule($_)
}
# Create new access rules
$writeRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$identityReference,
[System.DirectoryServices.ActiveDirectoryRights]::WriteProperty,
[System.Security.AccessControl.AccessControlType]::Allow,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendants,
$guidKeyCredentialLink)
$readRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$identityReference,
[System.DirectoryServices.ActiveDirectoryRights]::ReadProperty,
[System.Security.AccessControl.AccessControlType]::Allow,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendants,
$guidKeyCredentialLink)
# Set general read permission (for descendant user objects)
$readAllRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$identityReference,
[System.DirectoryServices.ActiveDirectoryRights]::GenericRead,
[System.Security.AccessControl.AccessControlType]::Allow,
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendants,
[guid]::Empty.ToString())
# Add access rules and commit changes
$acl.AddAccessRule($writeRule)
$acl.AddAccessRule($readRule)
$acl.AddAccessRule($readAllRule)
$adsi.ObjectSecurity = $acl
$adsi.CommitChanges()
Write-Output "Permissions for msDS-KeyCredentialLink were successfully set on the AdminSDHolder object."
} catch {
Write-Error "An error occurred while setting msDS-KeyCredentialLink permissions on the AdminSDHolder object: $_"
}
}
# Run the function
Set-KeyCredentialLinkPermissions -groupName "Key Admins" -userToAdd "octo"
但是,运行代码时出现以下错误:
Set-KeyCredentialLinkPermissions: C:\Users\Administrator\Desktop\msDS-KeyCredentialLink.ps1:80
Line |
80 | Set-KeyCredentialLinkPermissions -groupName "Key Admins" -userToAdd " …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| AdminSDHolder nesnesinde msDS-KeyCredentialLink izinleri ayarlanirken bir hata olustu: Cannot find an overload
| for "ActiveDirectoryAccessRule" and the argument count: "5".
我创建了一个 PowerShell 脚本来实现以下目标:
将用户“octo”添加到“Key Admins”组。
将“Key Admins”组添加到 AdminSDHolder 对象。
为“Key Admins”组的 msDS-KeyCredentialLink 属性设置写入和读取权限。
注意:在当前情况下,您针对的是 .NET 类型的构造函数,但由于构造函数只是特殊方法,因此以下内容也适用于方法。
您正在尝试调用这个 5 参数构造函数的重载
[System.DirectoryServices.ActiveDirectoryAccessRule]
。不幸的是,PowerShell 发出的错误消息
Cannot find an overload for "ActiveDirectoryAccessRule" and the argument count: "5"
——在当前情况下具有误导性,因为问题不在于参数的数量,而在于它们的类型。如果参数类型存在问题,则意味着参数类型与形参类型不完全匹配,或者无法转换为形参类型。
虽然 PowerShell 在自动类型转换方面非常灵活,但它会尝试找到合适的重载,但最好使参数类型与参数类型完全匹配,以确保概念清晰和长期稳定性。
您的具体问题主要是打字错误:
[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendants
必须是[System.DirectoryServices.ActiveDirectorySecurityInheritance]::Descendents
(e
而不是a
最后一个元音) - 尽管a
拼写正确,因为它指的是名词,所以在语言学上是正确的拼写。如果错误消息包含传递的参数类型(将来可能会这样),问题就会很明显:由于没有
[System.DirectoryServices.ActiveDirectorySecurityInheritance]
名为的静态属性Descendants
,整个表达式的计算结果为$null
,这会阻止 PowerShell 找到正确的过载。如果你使用了或以上版本,PowerShell 将会报告尝试访问不存在的属性的错误;但是,它有明显的缺陷:
Set-StrictMode
-Version 2
Set-StrictMode
Set-StrictMode
是动态作用域而非词法作用域,这意味着从其有效作用域中调用的所有代码也会受到影响 —— 并且此类代码可能不是为此设计的,因此会中断;提供词法作用域严格模式来补救该问题正是本 RFC的主题。使用
Set-StrictMode -Version 2
或更高版本时,.Count
统一 PowerShell 标量和集合处理的隐式添加的属性将不可用 - 这应被视为错误,已在GitHub 问题 #2798中报告。请注意,PowerShell 可以自由地将枚举值的字符串表示形式转换为后者,因此如果您尝试传递需要
'Descendants'
a 的上下文,即使没有严格模式,[System.DirectoryServices.ActiveDirectorySecurityInheritance]
也会发生错误。因此,为了避免在任何严格模式下引用不存在的枚举值,您可以在设计时使用制表符完成,或者使用强制类型转换,在这种情况下问题就会变得明显:
此外,为了实现精确类型匹配,
[guid]::Empty.ToString()
应该是[guid]::Empty
,并且$guidKeyCredentialLink
应该是[guid] $guidKeyCredentialLink
最后,您应该避免在调用中使用伪方法语法
New-Object
:New-Object SomeType(arg1, ...)
使用-而不是New-Object SomeType [-ArgumentList] arg1, ...
,PowerShell cmdlet、脚本和函数的调用方式与shell 命令类似,而不是方法。也就是说,参数列表周围没有括号,参数以空格分隔(根据需要,将数组,
构造为单个参数)。有关详细信息,请参阅此答案。-ArgumentList
但是,如果使用 PSv5+构造函数调用方法(即使用内部静态方法),则需要方法语法
[SomeType]::new()
,如下所示,这通常比使用更可取。::new()
New-Object
总而言之,使用最后一个构造函数调用作为示例:
[1] 这是 PowerShell 作为后期绑定语言的不可避免的结果,也是为什么如果可用的话,PowerShell 原生解决方案通常比 .NET 方法调用更受欢迎的原因。另一种方法是精确
匹配构造函数/方法签名,必要时使用强制转换,这是保证长期稳定性的唯一方法。 有关影响方法的实际示例(在 .NET (Core) 和PowerShell (Core) 7中添加了新的重载) ,请参阅此答案的底部部分。
System.String.Split