如何过滤仅包含用户对象的顶层OU、容器及组?
解决AD查询中筛选仅含用户对象的顶层OU/容器/组问题
首先得明确一个关键限制:LDAP本身没办法在单一查询里直接过滤包含特定子对象的容器/组,因为LDAP查询是针对对象自身的属性,而不是它的子对象或成员关系。你当前的过滤器只是筛选出了符合类型的对象,但没有检查这些对象下面有没有计算机,所以才会返回包含计算机的OU/容器。
要实现你的需求,需要分两步走:先拿到所有目标类型的顶层对象,再逐个检查这些对象是否包含计算机(无论是子对象还是组成员)。
第一步:筛选顶层目标对象
先修正你的过滤器,去掉inetOrgPerson(这是用户对象类型,不是容器/组/OU),只保留你需要的顶层容器、OU、组和域对象:
(|(objectclass=domain)(objectclass=domainDNS)(objectclass=organization)(objectclass=organizationalunit)(objectclass=group)(objectclass=groupOfNames)(&(objectclass=container)(!cn=computers)))
这个过滤器会帮你拿到根域下所有符合类型的直接子对象(也就是你说的顶层对象)。
第二步:逐个检查是否包含计算机
对每个筛选出来的对象,我们需要判断它下面有没有计算机:
- 对于OU/容器/域:检查其下所有子对象(包括子OU)是否存在计算机;
- 对于组:检查其成员列表中是否包含计算机。
下面是C#的实现示例,用DirectorySearcher来完成这个逻辑,同时做了性能优化(找到一个计算机就停止查询):
using System.DirectoryServices; // 替换成你的域路径 var rootDomainPath = "LDAP://DC=yourdomain,DC=com"; using (var rootEntry = new DirectoryEntry(rootDomainPath)) { // 第一步:获取所有顶层目标对象 var topLevelSearcher = new DirectorySearcher(rootEntry) { Filter = "(|(objectclass=domain)(objectclass=domainDNS)(objectclass=organization)(objectclass=organizationalunit)(objectclass=group)(objectclass=groupOfNames)(&(objectclass=container)(!cn=computers)))", SearchScope = SearchScope.OneLevel, // 只查根域的直接子对象(顶层) PropertiesToLoad = { "distinguishedName", "name", "objectClass" } }; foreach (SearchResult result in topLevelSearcher.FindAll()) { var dn = result.Properties["distinguishedName"][0].ToString(); var objectClasses = result.Properties["objectClass"]; bool isGroup = objectClasses.Contains("group") || objectClasses.Contains("groupOfNames"); bool hasComputer = false; using (var targetEntry = new DirectoryEntry($"LDAP://{dn}")) { DirectorySearcher computerChecker; if (isGroup) { // 检查组是否包含计算机成员 computerChecker = new DirectorySearcher(targetEntry) { Filter = $"(&(objectClass=computer)(memberOf:1.2.840.113556.1.4.1941:={dn}))", PropertiesToLoad = { "distinguishedName" }, SizeLimit = 1 // 找到一个就停止,提升性能 }; } else { // 检查OU/容器下是否有计算机子对象 computerChecker = new DirectorySearcher(targetEntry) { Filter = "(objectClass=computer)", SearchScope = SearchScope.Subtree, // 检查所有层级的子对象 PropertiesToLoad = { "distinguishedName" }, SizeLimit = 1 // 找到一个就停止,提升性能 }; } var computerResult = computerChecker.FindOne(); hasComputer = computerResult != null; } if (!hasComputer) { // 这个对象符合要求,执行你的业务逻辑 Console.WriteLine($"符合条件的对象: {result.Properties["name"][0]} ({dn})"); // 比如添加到结果列表中 } } }
关键说明
- 性能优化:设置
SizeLimit = 1,只要找到一个计算机就停止查询,避免遍历所有子对象/成员; - 组的特殊处理:用LDAP的
1.2.840.113556.1.4.1941链式匹配规则,可以直接检查组的所有嵌套成员中是否有计算机; - 顶层对象控制:第一个查询用
SearchScope.OneLevel,确保只获取根域的直接子对象,不会递归到子OU。
这样就能精准筛选出仅包含用户对象的顶层OU、容器和组了。
内容的提问来源于stack exchange,提问作者Imran Yaseen
相关产品推荐
相关产品推荐

