Active Directory的DirectoryEntry与DirectorySearcher初识及Filter语法
前言
增删改查,我想查询是最先要说的一个了。本章主要记录使用.NET Framework进行对域控服务器对象的查询操作,介绍DirectoryEntry与DirectorySearcher(搜索器)及Filter(搜索过滤器)语法,并对AD对象常用属性做记录。
DirectoryEntry与DirectorySearcher
使用C#语言对域控服务器的AD对象进行查询操作,DirectoryEntry和DirectorySearcher是必须要了解的两个类。System.DirectoryServices 命名空间用以从托管代码简便地访问 Active Directory。该命名空间包含了两个组件类,即DirectoryEntry和DirectorySearcher,它们使用AD服务接口(ADSI)技术。
DirectoryEntry:我们知道Active Directory中的数据是树状的,并且是层次型存储。而DirectoryEntry类就是为了封装 Active Directory 层次结构中的节点或对象。使用此类绑定到对象、读取属性和更新特性。DirectoryEntry 与帮助器类一起为生存期管理和导航方法提供支持,包括创建、删除、重命名、移动子节点和枚举子级。
https://msdn.microsoft.com/zh-cn/library/system.directoryservices.directoryentry_members(v=vs.80).aspx
DirectorySearcher:顾名思义这个对象是主要执行针对Active Directory域服务的查询。
https://msdn.microsoft.com/zh-cn/library/system.directoryservices.directorysearcher(v=vs.110).aspx
目前我的域控服务器在域上AD对象结构如下:

一段示例代码,目的是查询用户李四
static void Main(string[] args)
{
//声明一个AD对象搜索器
DirectorySearcher searcher = new DirectorySearcher();
//设置此搜索器的搜索起点
searcher.SearchRoot = DomainRootEntry();
//设置此搜索器的搜索语句
searcher.Filter = "(&(objectClass=user)(name=李四))";
//设置此搜索器的查询范围
searcher.SearchScope = SearchScope.Subtree;
//执行查询,有FindOne与FindAll之别
SearchResult result = searcher.FindOne();
if (result != null)
{
//转换为李四对象
DirectoryEntry userEntry = result.GetDirectoryEntry();
}
}
/// <summary>
/// 域控服务器IP
/// </summary>
private static string DomainServiceIP = "192.168.241.3";
/// <summary>
/// 域控服务器用户名
/// </summary>
private static string UserName = @"Domain";
/// <summary>
/// 域控服务器密码
/// </summary>
private static string Password = "p@ssw0rd"; /// <summary>
/// 获取域控服务器中域节点对象
/// </summary>
public static DirectoryEntry DomainRootEntry()
{
DirectoryEntry rootEntry = null;
try
{
rootEntry = new DirectoryEntry("LDAP://" + DomainServiceIP, UserName, Password);
return rootEntry;
}
catch (Exception ex)
{
throw ex;
}
}

这里的DirectoryEntry对象封装 Active Directory 域层次结构中的节点对象。通过DirectorySearcher搜索器来查询用户李四。如代码所示DirectorySearcher对象使用有几个地方要了解。
SearchRoot:获取或设置一个值(DirectoryEntry对象,一般为DC或者OU),该值指示 Active Directory 域服务层次结构中的节点,从该节点处开始搜索。说白了就是说我这个查询器查询从这个节点开始向下查询包括这个节点。
SearchScope:获取或设置指示服务器遵循的搜索范围的值。为SearchScope的enmu类型。
//指定使用 System.DirectoryServices.DirectorySearcher 对象执行的目录搜索的可能范围。
public enum SearchScope
{
// 将搜索限于基对象。结果最多包含一个对象。当 System.DirectoryServices.DirectorySearcher.AttributeScopeQuery
// 属性指定用于某一搜索时,搜索范围必须设置为 System.DirectoryServices.SearchScope.Base。
Base = ,
// 搜索基对象的直接子对象,但不搜索基对象。
OneLevel = ,
// 搜索整个子树,包括基对象及其所有子对象。如果未指定目录搜索的范围,则执行 System.DirectoryServices.SearchScope.Subtree
// 类型的搜索。
Subtree =
}
FindOne();与FindAll();的区别:FindOne执行搜索返回搜索过程中找到的第一项,返回结果为一个System.DirectoryServices.SearchResult对象。而FindAll执行搜索并返回找到的项的集合,返回结果是System.DirectoryServices.SearchResultCollection对象。
剩下的就是这个Filter比较复杂了,我们继续往下看。
Filter语法详解及属性扩充
Filter:(官方解读为:搜索过滤器)它为DirectorySearcher(搜索器)定义一个搜索条件,为的是使我们的搜索器更有效的搜索。有点像ADO中的T-SQL语句。Filter属性值以 LDAP 格式表示的筛选条件,用Unicode字符串表示。下表列出了一些例子。
| Search filter(搜索过滤器) | Description(描述) |
| "(objectClass=*)" | 所有的对象。 |
| "(&(objectCategory=person)(objectClass=user)(!cn=andy))" | 所有的用户对象,但“andy”除外 |
| "(sn=sm*)" | 所有对象的满足姓氏从“SM”开头。 |
| "(&(objectClass=user)(name=李四))" | 所有名称为李四的用户对象 |
Filter语法详解:
表达式:属性名=Value
通配符:“*”,该字符出现在表达式Value中,匹配该字符位置后的内容,类似于SQL中的“%”;例子如下:
|
Description(描述) | |
| ”(objectClass=*)“ | 得到所有对象 | |
| “(cn=*bob*)” | 得到的对象,名称含有“bob”: | |
| ”(&(objectClass=user)(email=*))“ | 得到包含电子邮件属性的所有用户: |
逻辑运算符:
| Logical operator(逻辑运算符) | Description(描述) |
| = | 等于 |
| & | 和 |
| | | 或 |
| ! | 非 |
| ~= | 约等于 |
| <= | 字典序小于或者等于 |
| >= | 字典序大于或者等于 |
语法类型:(Key=Value)为一个表达式,两个表达式满足某些条件(|或、&且、!非)则放在两个表达前面并用括号括起来。如:(&(objectClass=user)(mobile=132*)) ,电话为132开头的所有用户。(&(表达式1=value)(表达式2=value)),该filter结果为取表达式1和表达式2同时匹配的内容。
特殊字符:如果以下任何特殊字符必须出现在搜索过滤的文字中,他们必须通过的转义替换。
| ASCII字符 | 转义替代 |
| * | \2a |
| ( | \28 |
| ) | \29 |
| \ | \5c |
| NULL | \00 |
| / | \2f |
DirectorySearcher.Filter类型属性扩充说明(不区分大小写):
| 筛选条件 | 值 |
| 域 | (objectClass=domainDNS) |
| 组织单位 | (objectClass=organizationalUnit) |
| 用户 | (&(objectCategory=person)(objectClass=user))或者(&(objectClass=User)(!objectClass=computer)) |
| 计算机 | (objectCategory=computer) |
| 组 | (objectCategory=group) |
| 联系人 | (objectCategory=contact) |
| 共享文件夹 | (objectCategory=volume) |
| 打印机 | (objectCategory=printQueue) |
以上是一些常用类型检索条件,值得注意的是(objectClass=user)并不只是检索用户还包括计算机。所以要要做处理。当然检索的条件不知以上这些。AD中对象的属性都可以做检索条件,我们最后看看AD中的对象属性有哪些是我们常用的。
Active Directory常用属性
用户(User)常用选项卡中的属性

| 选项卡项名 | 属性名 | 备注 |
| 名称 | name | 在同一节点下唯一,string |
| 姓(L) | sn | string |
| 名(F) | givenName | string |
| 英文缩写(I) | initials | string |
| 显示名称(S) | displayName | 域内不唯一,但是在同一个组织单位内唯一 |
| 描述(D) | description | string[] |
| 办公室(C) | physicalDeliveryOfficeName | string |
| 电话号码(T) | telephoneNumber | string |
| 电子邮件(M) | string | |
| 网页(W) | wWWHomePage | string |

| 选项卡项名 | 属性名 | 备注 |
| 用户登录名(U) | userPrincipalName | 全域内唯一,string |
| 用户登录名(Windows 2000 以前版本)(W) | sAMAccountName | 全域内唯一,string |

| 选项卡项名 | 属性名 | 备注 |
| 国家/地区(O) | co | string |
| 省/自治区(V) | st | string |
| 市/县(C) | l | string |
| 街道(S) | streetAddress | string |
| 邮政信箱(B) | postOfficeBox | string[] |
| 邮政编码(Z) | postalCode | string |

| 选项卡项名 | 属性名 | 备注 |
| 家庭电话(M) | homePhone | string |
| 寻呼机(P) | pager | string |
| 移动电话(B) | mobile | string |
| 传真(F) | facsimileTelephoneNumber | string |
| IP电话(I) | ipPhone | string |
| 注释 | info | string |

| 选项卡项名 | 属性名 | 备注 |
| 公司(C) | company | string |
| 部门(D) | department | string |
| 职务(J) | title | string |
| 经理-姓名(N) | manager | string |
| 直接下属(E) | directReports | string[] |
组织单位(Organizational Unit)常用选项卡中的属性

| 选项卡项名 | 属性名 | 备注 |
| 名称 | name | 在同一节点下唯一,string |
| 描述(D) | description | string[] |
| 国家/地区(O) | co | string |
| 邮政编码(Z) | postalCode | string |
| 省/自治区(V) | st | string |
| 市/县(C) | l | string |
| 街道(S) | street | string |
Active Directory的隐藏通用属性
这一部分属性,在选项卡上是看不到的,必须在【属性编辑器】中才能查看到:
| 属性 | 备注 |
| objectGUID | 全域内唯一,对象创建时自动生成的,16进制所以在DirecotryEntry中接受时要做数据处理。 |
| distinguishedName | 全域内唯一,对象创建或者移动时自动生成。详细请看上章。 |
| objectClass | 对象创建时自动创建 |
| cn | 常用于User或者Computer,与name相同。 |
| ou | 常用于Ou,与name同属性。 |
大约整理出这些常用属性,若想查看更多有两种方式:第一种查看属性的属性编辑器,第二种遍历DirectoryEntry.Properties.PropertyNames;
结语
这些属性根据业务场景不同用的多少也会不同。有时候可能会使用一些不常用的属性存储与业务处理有关的数据,因为AD中的数据存储不想关系型数据库,所以在AD中一些不常用的属性我们会根据不同业务场景去为逻辑变成做铺垫。Filter语法的话其实和LDAP协议有着很密切的关系但这里就不说了。主要是DirectoryEntry和DirectorySearcher这两个类对象,在后面DirectoryEntry做AD编程时将无处不在,它是一个入口。鉴于目前.NET Core 没有更新System.DirectoryServices;。所以以后若使用PowerShell那就另外再说了。
本章最后更新时间:2017年4月23日18:10:13
作者:IFire47 出处:http://www.cnblogs.com/IFire47/
Active Directory的DirectoryEntry与DirectorySearcher初识及Filter语法的更多相关文章
- C# AD(Active Directory)域信息同步,组织单位、用户等信息查询
示例准备 打开上一篇文章配置好的AD域控制器 开始菜单-->管理工具-->Active Directory 用户和计算机 新建组织单位和用户 新建层次关系如下: 知识了解 我们要用C# ...
- C#操作Active Directory(AD)详解
1. LDAP简介 LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务.目录服务是一种特殊的数据库系统,其专门 ...
- 如何通过使用窗体身份验证和 Visual C#.NET 对 Active Directory 验证身份
本分步指南演示如何在 ASP.NET 应用程序如何使用窗体身份验证允许用户使用轻型目录访问协议 (LDAP),对 Active Directory 进行验证.经过身份验证的用户重定向之后,可以使用Ap ...
- 操作Active Directory C#
.Net平台操作活动目录Active Directory,使用System.DirectoryServices.ActiveDirectory,主要是User OU 和Group的操作. 代码运行了一 ...
- Active Directory组织单位(Organizational Unit)操作汇总
前言 本章聊Active Directory的组织单位(OU)的新增.修改.移动等操作,使用.NET Framework 为我们提供的System.DirectoryServices程序集. 不积跬步 ...
- Active Directory的LDAP协议与DN(Distinguished Name)详解
前言 光copy几段代码的文章没什么意思,本章上最基础的代码,主要是为了从编程方面聊LDAP和DN,其它的后面聊,一步步慢慢来吧. Active Directory编程须知 1.域控服务器: Wind ...
- 通过LDAP验证Active Directory服务
原文地址:http://www.byywee.com/page/M0/S215/215725.html C#: using System; using System.Collections.Gener ...
- CAS FOR WINDOW ACTIVE DIRECTORY SSO单点登录
一.CAS是什么? CAS(Central Authentication Service)是 Yale 大学发起的一个企业级的.开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(支持 ...
- AD域的安装(在Windows Server 2003中安装Active Directory)
在Active Directory中提供了一组服务器作为身份验证服务器或登录服务器,这类服务器被称作域控制器(Domain Controller,简称DC).建立一个AD域的过程实际就是在一台运行Wi ...
随机推荐
- hihoCoder #1072 辅导
题意 $\DeclareMathOperator{\lcm}{lcm}$选 $k$ ($k\le 10$) 个 $1$ 到 $n$($n\le 10^9$)之间的整数(可以相同),使得 $\lcm(a ...
- linux tomcat安装(二)
安装步骤: 1.下载 Tomcat 下载 apache-tomcat-7.0.69.tar.gz(官方网址:http://tomcat.apache.org/) 2.解压 Tomcat 解压 apac ...
- C#中DataTable中Rows.Add 和 ImportRow 对比
最近参加项目中,数据操作基本都是用DataTable的操作,老代码中有些地方用到DataTable.Rows.Add又有些代码用的DataTable.ImportRow,于是就对比了一下 VS查询说明 ...
- gcc 内置函数
关于gcc内置函数和c隐式函数声明的认识以及一些推测 最近在看APUE,不愧是经典,看一点就收获一点.但是感觉有些东西还是没说清楚,需要自己动手验证一下,结果发现需要用gcc,就了解一下. 有时候 ...
- Charger Warning Message
使用 PMIC_RGS_VCDT_HV_DET 判斷 charger 是否有 ovp. LV_VTH : 4.15V
- HDU 4722:Good Numbers(数位DP)
类型:数位DP 题意:定义一个Good Number 为 一个数所有位数相加的和%10==0.问[A,B]之间有多少Good Number. 方法: 正常“暴力”的定义状态:(i,d,相关量) 定义d ...
- AC日记——Milking Grid poj 2185
Milking Grid Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 8314 Accepted: 3586 Desc ...
- Codeforces 691F Couple Cover
可以暴力预处理出每一种小于3000000的乘积有几种.询问的时候可以用总的方案减去比p小的有几种o(1)输出. #pragma comment(linker, "/STACK:1024000 ...
- SpringCloud 分布式事务解决方案
目录 TX-LCN分布式事务框架 TX-LCN分布式事务框架 随着互联化的蔓延,各种项目都逐渐向分布式服务做转换.如今微服务已经普遍存在,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生. 分 ...
- HDU 1045 Fire Net 状压暴力
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others) ...