ADSI查询Active Directory组出现重复SID问题的解决方法
问题解决:不同域同名组SID解析错误的修复
问题背景
我使用修改后的ADSI函数获取本地管理员组成员的SID。优先考虑Get-LocalGroupMember,但由于Active Directory不可达时该cmdlet无法仅通过SID正常访问,因此必须依赖ADSI实现。
当前遇到的问题:当存在两个名称相同但所属域不同的AD组时,函数返回的SID完全一致,与实际情况不符,示例如下:
| 用户名 | 类型 | SID | 路径 |
|---|---|---|---|
| Domain Users | 组 | S-1-5-21-1390067357-2000478354-839522115-513 | DOMAIN1/Domain Users |
| Domain Users | 组 | S-1-5-21-1390067357-2000478354-839522115-513 | DOMAIN2/Domain Users |
问题原因
原函数中创建System.Security.Principal.NTAccount对象时,仅传入了用户名$username,未包含所属域信息。系统解析时会默认使用当前域或出现歧义,导致不同域的同名组被错误解析为同一个SID。
修复方案
从ADSI返回的AdsPath(即函数中的$path)中拆分出域和用户名,使用域\用户名的完整格式创建NTAccount对象,确保解析时能精准定位到对应域的组。
修改后的函数如下:
Function Get-LocalGroupMembers { [Cmdletbinding()] Param( [Parameter(Mandatory=$true)] [string]$GroupName ) [adsi]$adsiGroup = "WinNT://$($env:COMPUTERNAME)/$GroupName,group" $adsiGroup.Invoke('Members') | ForEach-Object{ $username = $_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null) $path = $_.GetType().InvokeMember('AdsPath','GetProperty',$null,$_,$null).Replace('WinNT://','') $class = $_.GetType().InvokeMember('Class','GetProperty',$null,$_,$null) # 从Path中拆分域和名称,格式为DOMAIN/Username $pathParts = $path -split '/', 2 if ($pathParts.Count -eq 2) { $ntAccountName = "$($pathParts[0])\$($pathParts[1])" $userObj = New-Object System.Security.Principal.NTAccount($ntAccountName) } else { # 处理本地账户或格式异常的情况 $userObj = New-Object System.Security.Principal.NTAccount($username) } try{ $sid = $userObj.Translate([System.Security.Principal.SecurityIdentifier]) }catch{ $sid = $userObj } [pscustomobject]@{ Username = $username Type = $class SID = $sid.Value # 直接返回SID字符串,避免对象显示问题 Path = $path } } }
关键修改点
- 拆分路径获取完整账户名:通过
$path -split '/', 2将DOMAIN/Username格式的路径拆分为域和用户名,组合成域\用户名的完整标识。 - 精准创建NTAccount对象:使用完整账户名创建对象,确保系统能正确解析对应域的安全主体。
- 优化SID输出:将
$sid.Value赋值给SID字段,直接返回SID字符串,避免输出时显示对象类型信息。
经过上述修改后,不同域的同名组将返回各自正确的SID,解决了之前的解析错误问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

