前言
增刪改查,我想查詢是最先要說的一個了。本章主要記錄使用.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對象結構如下:
一段示例代碼,目的是查詢用戶李四
1 static void Main(string[] args) 2 { 3 //聲明一個AD對象搜索器 4 DirectorySearcher searcher = new DirectorySearcher(); 5 //設置此搜索器的搜索起點 6 searcher.SearchRoot = DomainRootEntry(); 7 //設置此搜索器的搜索語句 8 searcher.Filter = "(&(objectClass=user)(name=李四))"; 9 //設置此搜索器的查詢范圍 10 searcher.SearchScope = SearchScope.Subtree; 11 //執行查詢,有FindOne與FindAll之別 12 SearchResult result = searcher.FindOne(); 13 if (result != null) 14 { 15 //轉換為李四對象 16 DirectoryEntry userEntry = result.GetDirectoryEntry(); 17 } 18 } 19 /// <summary> 20 /// 域控服務器IP 21 /// </summary> 22 private static string DomainServiceIP = "192.168.241.3"; 23 /// <summary> 24 /// 域控服務器用戶名 25 /// </summary> 26 private static string UserName = @"Domain"; 27 /// <summary> 28 /// 域控服務器密碼 29 /// </summary> 30 private static string Password = "p@ssw0rd"; 31 32 /// <summary> 33 /// 獲取域控服務器中域節點對象 34 /// </summary> 35 public static DirectoryEntry DomainRootEntry() 36 { 37 DirectoryEntry rootEntry = null; 38 try 39 { 40 rootEntry = new DirectoryEntry("LDAP://" + DomainServiceIP, UserName, Password); 41 return rootEntry; 42 } 43 catch (Exception ex) 44 { 45 throw ex; 46 } 47 }
這里的DirectoryEntry對象封裝 Active Directory 域層次結構中的節點對象。通過DirectorySearcher搜索器來查詢用戶李四。如代碼所示DirectorySearcher對象使用有幾個地方要了解。
SearchRoot:獲取或設置一個值(DirectoryEntry對象,一般為DC或者OU),該值指示 Active Directory 域服務層次結構中的節點,從該節點處開始搜索。說白了就是說我這個查詢器查詢從這個節點開始向下查詢包括這個節點。
SearchScope:獲取或設置指示服務器遵循的搜索范圍的值。為SearchScope的enmu類型。
1 //指定使用 System.DirectoryServices.DirectorySearcher 對象執行的目錄搜索的可能范圍。 2 public enum SearchScope 3 { 4 // 將搜索限於基對象。結果最多包含一個對象。當 System.DirectoryServices.DirectorySearcher.AttributeScopeQuery 5 // 屬性指定用於某一搜索時,搜索范圍必須設置為 System.DirectoryServices.SearchScope.Base。 6 Base = 0, 7 // 搜索基對象的直接子對象,但不搜索基對象。 8 OneLevel = 1, 9 // 搜索整個子樹,包括基對象及其所有子對象。如果未指定目錄搜索的范圍,則執行 System.DirectoryServices.SearchScope.Subtree 10 // 類型的搜索。 11 Subtree = 2 12 }
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/