C# WinForm获取Active Directory用户直接所属组及报错解决
获取AD用户直接隶属组时1355错误的解决方法
问题背景
使用C# Windows Form程序获取Active Directory用户的**直接隶属组(Member of,不含嵌套组)**时,调用GetGroups()方法仅对部分用户有效,多数用户触发错误:Information about the domain could not be retrieved (1355)。
原尝试代码:
public List<string> GetUserImmediateGroups(string userName) { List<string> groupNames = new List<string>(); using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) { UserPrincipal user = UserPrincipal.FindByIdentity(ctx, userName); if (user != null) { // 获取用户直接隶属的组 PrincipalSearchResult<Principal> userGroups = user.GetGroups(); foreach (GroupPrincipal group in userGroups.OfType<GroupPrincipal>()) { groupNames.Add(group.SamAccountName); } } return groupNames; // 返回直接组名称列表 } }
错误信息:
Information about the domain could not be retrieved (1355).
错误原因
GetGroups()方法特性:该方法会自动解析嵌套组并尝试获取所有组的完整域信息,若部分组所在域无法被当前上下文访问(如跨域组、域控制器不可达),就会抛出1355错误。- 默认
PrincipalContext局限性:未指定具体域名时,上下文可能无法正确定位用户所在域,导致域信息检索失败。 - 权限或域控制器问题:程序运行账号无足够权限访问部分组的域信息,或目标域控制器离线/不可用。
解决方案
方法一:直接读取MemberOf属性(推荐)
MemberOf属性存储的是用户直接隶属组的DN(区分名),无需解析嵌套组,也不会触发跨域查询,彻底规避1355错误。
修改后代码:
public List<string> GetUserImmediateGroups(string userName) { List<string> groupNames = new List<string>(); using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) { UserPrincipal user = UserPrincipal.FindByIdentity(ctx, userName); if (user != null) { // 获取MemberOf属性的原始值(直接组的DN) var memberOfValues = user.GetUnderlyingObjectProperties()["memberOf"]; if (memberOfValues != null) { foreach (string dn in (IEnumerable)memberOfValues) { // 从DN中提取组名(格式:CN=组名,OU=...) int cnIndex = dn.IndexOf("CN=") + 3; int commaIndex = dn.IndexOf(",", cnIndex); if (cnIndex > 2 && commaIndex > cnIndex) { string groupName = dn.Substring(cnIndex, commaIndex - cnIndex); groupNames.Add(groupName); } } } } return groupNames; } }
方法二:指定具体域名初始化PrincipalContext
若必须使用GetGroups()方法,明确指定用户所在域名,避免上下文自动解析出错:
// 替换为实际域名,例如"contoso.com" using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "your-domain-name")) { // 后续逻辑保持不变 }
方法三:添加异常处理,跳过无法访问的组
若要保留GetGroups()逻辑,添加try-catch跳过出错的组,确保获取可用的组信息:
public List<string> GetUserImmediateGroups(string userName) { List<string> groupNames = new List<string>(); using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) { UserPrincipal user = UserPrincipal.FindByIdentity(ctx, userName); if (user != null) { PrincipalSearchResult<Principal> userGroups = user.GetGroups(); foreach (Principal principal in userGroups) { try { if (principal is GroupPrincipal group) { groupNames.Add(group.SamAccountName); } } catch (DirectoryServicesCOMException ex) { // 跳过无法获取信息的组,可按需记录日志 if (ex.ErrorCode == 1355) { continue; } throw; // 其他异常重新抛出 } } } return groupNames; } }
说明
- 方法一最可靠,完全贴合“仅获取直接组”的需求,无额外域查询操作。
- 若需要组的更多属性(如描述、SID),可通过组的DN查询对应的
GroupPrincipal,但需注意添加异常处理。
内容的提问来源于stack exchange,提问作者Kanishka Kularathna
相关产品推荐
相关产品推荐

