C#如何从Active Directory获取自定义安全组
筛选AD中的自定义安全组
好问题!确实Active Directory里没有专门标记「自定义组」的内置属性,但我们可以通过组所在的OU/容器路径来间接实现筛选——毕竟系统默认的安全组基本都集中在Builtin、Users这些默认容器里,而你自己创建的组大概率会放在自定义OU下。
先提个小细节:你当前代码里的lstAdGroups.Items.Clear();是放在foreach循环内部的,这会导致每次循环都清空列表,最后只会显示最后一个找到的组,记得把它移到循环外面哦!
下面给你两种可行的实现方案:
方案一:用LDAP筛选器在AD服务器端过滤(效率更高)
这种方式直接在AD服务器上完成筛选,不用把所有组都拉到客户端再过滤,性能更好。核心思路是构造LDAP筛选条件,只返回安全组,且排除Builtin和Users容器下的组。
try { Logging.LogMessageToFile("Reading custom Security Groups from AD."); PrincipalContext ctx = new PrincipalContext(ContextType.Domain); // 获取域的根DN,用来拼接默认容器的完整DN DirectoryEntry domainEntry = ctx.GetUnderlyingObject() as DirectoryEntry; string domainDN = domainEntry.Properties["distinguishedName"].Value.ToString(); string usersContainerDN = $"CN=Users,{domainDN}"; string builtinContainerDN = $"CN=Builtin,{domainDN}"; // 构造LDAP筛选器: // - objectCategory=group:筛选组对象 // - groupType:1.2.840.113556.1.4.803:=2:筛选安全组(位运算匹配groupType中的安全组标记) // - !distinguishedName=*{usersContainerDN}:排除Users容器下的组 // - !distinguishedName=*{builtinContainerDN}:排除Builtin容器下的组 string ldapFilter = $"(& (objectCategory=group) (groupType:1.2.840.113556.1.4.803:=2) (!distinguishedName=*{usersContainerDN}) (!distinguishedName=*{builtinContainerDN}) )"; GroupPrincipal qbeGroup = new GroupPrincipal(ctx); qbeGroup.QueryFilter = new LDAPFilter(ldapFilter); PrincipalSearcher srch = new PrincipalSearcher(qbeGroup); // 先清空列表,再批量添加符合条件的组 lstAdGroups.Items.Clear(); foreach (var found in srch.FindAll()) { lstAdGroups.Items.Add(found); } } catch (Exception ex) { Logging.LogMessageToFile("Unexpected error reading custom Security Groups from AD: " + ex.Message); }
方案二:客户端遍历结果时过滤(更直观)
如果不想写LDAP筛选器,也可以先获取所有安全组,再在客户端过滤掉默认容器下的组:
try { Logging.LogMessageToFile("Reading custom Security Groups from AD."); PrincipalContext ctx = new PrincipalContext(ContextType.Domain); // 先筛选所有安全组 GroupPrincipal qbeGroup = new GroupPrincipal(ctx); qbeGroup.SecurityGroup = true; PrincipalSearcher srch = new PrincipalSearcher(qbeGroup); // 获取默认容器的完整DN DirectoryEntry domainEntry = ctx.GetUnderlyingObject() as DirectoryEntry; string domainDN = domainEntry.Properties["distinguishedName"].Value.ToString(); string usersContainerDN = $"CN=Users,{domainDN}"; string builtinContainerDN = $"CN=Builtin,{domainDN}"; lstAdGroups.Items.Clear(); foreach (GroupPrincipal found in srch.FindAll()) { // 检查组的DN是否以默认容器DN结尾,不是则添加到列表 bool isInDefaultContainer = found.DistinguishedName.EndsWith(usersContainerDN, StringComparison.OrdinalIgnoreCase) || found.DistinguishedName.EndsWith(builtinContainerDN, StringComparison.OrdinalIgnoreCase); if (!isInDefaultContainer) { lstAdGroups.Items.Add(found); } } } catch (Exception ex) { Logging.LogMessageToFile("Unexpected error reading custom Security Groups from AD: " + ex.Message); }
额外说明
- 如果你的环境中还有其他需要排除的默认容器(比如
Domain Controllers下的系统组),可以用同样的方式添加到筛选条件中。 - 极少数情况下,如果自定义组被误放在
Users容器中,这种方法会把它排除。如果需要兼容这种场景,可以考虑结合组的创建时间辅助筛选(系统组的创建时间通常和域创建时间一致,自定义组是之后创建的),但这种方式不如OU路径筛选可靠,优先推荐前者。
内容的提问来源于stack exchange,提问作者Rawns
相关产品推荐
相关产品推荐

