使用DirectoryEntry获取本地机器子条目时GUID全部重复,如何获取正确值?
问题原因
你遇到的GUID重复问题是WinNT目录服务提供程序的固有特性:该提供程序设计上没有为本地安全主体(用户、组、计算机账户等)暴露原生的对象GUID属性,你直接读取DirectoryEntry.Guid拿到的是WinNT提供程序返回的固定默认值,不是对应条目的唯一标识。
解决方案
方案1:使用System.DirectoryServices.AccountManagement 实现(推荐)
这是.NET官方封装的身份主体管理专用库,直接可以拿到正确的对象GUID,代码更简洁,也不需要手动处理WinNT提供程序的缺陷。
使用前需要先添加程序集引用System.DirectoryServices.AccountManagement,参考实现代码:
using System.DirectoryServices.AccountManagement; using System.Collections.Generic; public static List<(Guid ObjectGuid, string Sid, string Name, string ObjectType)> GetLocalMachineEntries() { List<(Guid ObjectGuid, string Sid, string Name, string ObjectType)> result = new(); // 连接本地计算机上下文 using PrincipalContext localContext = new PrincipalContext(ContextType.Machine); // 定义查询过滤,默认查询所有主体类型,也可指定UserPrincipal、GroupPrincipal等单独查询 using Principal queryFilter = new Principal(localContext); using PrincipalSearcher searcher = new PrincipalSearcher(queryFilter); foreach (Principal principal in searcher.FindAll()) { result.Add(( ObjectGuid: principal.Guid.Value, // 此处获取的即为真实唯一GUID Sid: principal.Sid.Value, Name: principal.Name, ObjectType: principal.StructuralObjectClass )); principal.Dispose(); } return result; }
该方案拿到的GUID是本地安全主体的真实唯一标识,仅在账户被删除重建时才会变更,修改用户名、组权限等操作都不会改变GUID,符合作为唯一标识的需求。未加入域的独立机器使用该方案不需要额外权限,普通用户权限即可正常读取所有公开的本地主体GUID。
方案2:基于现有DirectoryEntry代码适配获取GUID
如果你必须保留现有WinNT目录访问的代码逻辑,可以通过将条目SID转换为GUID的方式获取:本地账户的对象GUID实际存储在注册表路径HKEY_LOCAL_MACHINE\SECURITY\Policy\Secrets\下对应SID的子项中,也可以通过调用LsaLookupSids Win32 API传入SID获取对应的GUID。但这种方式需要处理权限问题(访问SECURITY注册表项需要管理员权限),实现复杂度远高于方案1,不推荐使用。
内容的提问来源于stack exchange,提问作者Smolakian
相关产品推荐
相关产品推荐

