接上篇 Windows Server 2008 R2 配置AD(Active Directory)域控制器
對(duì)AD域結(jié)合常見需求用C#進(jìn)行一些讀取信息的操作^_^!
- 打開上一篇文章配置好的AD域控制器
- 開始菜單-->管理工具-->Active Directory 用戶和計(jì)算機(jī)
- 新建組織單位和用戶


我們要用C#訪問Active Directory非常容易,主要用到
輕量目錄訪問協(xié)議 (LDAP)
System.DirectoryServices命名空間下的兩個(gè)組件類
DirectoryEntry和DirectorySeacher
示例在Framework 3.5下用Winform程序編寫
主要結(jié)合常見需求讀取組織單位(OU)及用戶(User)信息,以及同步組織單位和用戶的層次關(guān)系;
比較著重的還是用戶的信息,特別是賬號(hào)、郵箱、SID等信息;
- 下面我們開始連接域,并讀取出示例準(zhǔn)備中鍵好的組織單位和用戶
首先編寫代碼用LDAP嘗試對(duì)域進(jìn)行訪問
形式:LDAP://Domain
#region## 是否連接到域
/// <summary>
/// 功能:是否連接到域
/// 作者:Wilson
/// 時(shí)間:2012-12-15
/// http://msdn.microsoft.com/zh-cn/library/system.directoryservices.directoryentry.path(v=vs.90).aspx
/// </summary>
/// <param name="domainName">域名或IP</param>
/// <param name="userName">用戶名</param>
/// <param name="userPwd">密碼</param>
/// <param name="entry">域</param>
/// <returns></returns>
private bool IsConnected(string domainName, string userName, string userPwd, out DirectoryEntry domain)
{
domain = new DirectoryEntry();
try
{
domain.Path = string.Format("LDAP://{0}", domainName);
domain.Username = userName;
domain.Password = userPwd;
domain.AuthenticationType = AuthenticationTypes.Secure;
domain.RefreshCache();
return true;
}
catch(Exception ex)
{
LogRecord.WriteLog("[IsConnected方法]錯(cuò)誤信息:" + ex.Message);
return false;
}
}
#endregion
傳用參數(shù),調(diào)IsConnected方法,結(jié)果如下

#region## 域中是否存在組織單位
/// <summary>
/// 功能:域中是否存在組織單位
/// 作者:Wilson
/// 時(shí)間:2012-12-15
/// </summary>
/// <param name="entry"></param>
/// <param name="ou"></param>
/// <returns></returns>
private bool IsExistOU(DirectoryEntry entry, out DirectoryEntry ou)
{
ou = new DirectoryEntry();
try
{
ou = entry.Children.Find("OU=" + txtRootOU.Text.Trim());
return (ou != null);
}
catch(Exception ex)
{
LogRecord.WriteLog("[IsExistOU方法]錯(cuò)誤信息:" + ex.Message);
return false;
}
}
#endregion
傳入以數(shù),調(diào)用IsExistOU方法,結(jié)果如下

示例為了看出層次關(guān)系及導(dǎo)出信息是類型區(qū)分,給OU和User新建了一個(gè)實(shí)體類和一個(gè)類型的枚舉
#region## 類型
/// <summary>
/// 類型
/// </summary>
public enum TypeEnum : int
{
/// <summary>
/// 組織單位
/// </summary>
OU = 1,
/// <summary>
/// 用戶
/// </summary>
USER = 2
}
#endregion
#region## Ad域信息實(shí)體
/// <summary>
/// Ad域信息實(shí)體
/// </summary>
public class AdModel
{
public AdModel(string id, string name, int typeId, string parentId)
{
Id = id;
Name = name;
TypeId = typeId;
ParentId = parentId;
}
public string Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public string ParentId { get; set; }
}
#endregion
下面讀取信息

private List<AdModel> list = new List<AdModel>();
#region## 同步
/// <summary>
/// 功能:同步
/// 創(chuàng)建人:Wilson
/// 創(chuàng)建時(shí)間:2012-12-15
/// </summary>
/// <param name="entryOU"></param>
public void SyncAll(DirectoryEntry entryOU)
{
DirectorySearcher mySearcher = new DirectorySearcher(entryOU, "(objectclass=organizationalUnit)"); //查詢組織單位
DirectoryEntry root = mySearcher.SearchRoot; //查找根OU
SyncRootOU(root);
StringBuilder sb = new StringBuilder();
sb.Append("\r\nID\t賬號(hào)\t類型\t父ID\r\n");
foreach (var item in list)
{
sb.AppendFormat("{0}\t{1}\t{2}\t{3}\r\n", item.Id, item.Name, item.TypeId, item.ParentId);
}
LogRecord.WriteLog(sb.ToString());
MessageBox.Show("同步成功", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
Application.Exit();
}
#endregion
#region## 同步根組織單位
/// <summary>
/// 功能: 同步根組織單位
/// 創(chuàng)建人:Wilson
/// 創(chuàng)建時(shí)間:2012-12-15
/// </summary>
/// <param name="entry"></param>
private void SyncRootOU(DirectoryEntry entry)
{
if (entry.Properties.Contains("ou") && entry.Properties.Contains("objectGUID"))
{
string rootOuName = entry.Properties["ou"][0].ToString();
byte[] bGUID = entry.Properties["objectGUID"][0] as byte[];
string id = BitConverter.ToString(bGUID);
list.Add(new AdModel(id, rootOuName, (int)TypeEnum.OU, "0"));
SyncSubOU(entry, id);
}
}
#endregion
#region## 同步下屬組織單位及下屬用戶
/// <summary>
/// 功能: 同步下屬組織單位及下屬用戶
/// 創(chuàng)建人:Wilson
/// 創(chuàng)建時(shí)間:2012-12-15
/// </summary>
/// <param name="entry"></param>
/// <param name="parentId"></param>
private void SyncSubOU(DirectoryEntry entry, string parentId)
{
foreach (DirectoryEntry subEntry in entry.Children)
{
string entrySchemaClsName = subEntry.SchemaClassName;
string[] arr = subEntry.Name.Split('=');
string categoryStr = arr[0];
string nameStr = arr[1];
string id = string.Empty;
if (subEntry.Properties.Contains("objectGUID")) //SID
{
byte[] bGUID = subEntry.Properties["objectGUID"][0] as byte[];
id = BitConverter.ToString(bGUID);
}
bool isExist = list.Exists(d => d.Id == id);
switch (entrySchemaClsName)
{
case "organizationalUnit":
if (!isExist)
{
list.Add(new AdModel(id, nameStr, (int)TypeEnum.OU, parentId));
}
SyncSubOU(subEntry, id);
break;
case "user":
string accountName = string.Empty;
if (subEntry.Properties.Contains("samaccountName"))
{
accountName = subEntry.Properties["samaccountName"][0].ToString();
}
if (!isExist)
{
list.Add(new AdModel(id, accountName, (int)TypeEnum.USER, parentId));
}
break;
}
}
}
#endregion

調(diào)用SyncAll方法循環(huán)輸出list,結(jié)果如下,很清楚的可以看出層次關(guān)系
//ID 賬號(hào) 類型 父ID
//58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17 acompany 1 0
//FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B department01 1 58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
//47-9D-5B-91-60-22-D1-46-B0-CD-C7-B2-C7-D3-00-31 department03 1 FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B
//E3-AD-47-45-38-64-02-4D-B9-83-2C-50-67-50-4F-92 zw 2 47-9D-5B-91-60-22-D1-46-B0-CD-C7-B2-C7-D3-00-31
//8A-D4-23-18-F3-6F-E1-47-93-7A-CC-07-76-4B-E7-86 zhongw 2 FB-44-91-AE-AC-73-2B-4D-9F-01-B1-E2-16-D3-CB-1B
//BC-D0-34-85-67-2F-05-4D-B5-77-E3-F4-AD-51-45-02 department02 1 58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
//1C-13-FA-66-E4-51-65-49-8B-DC-22-60-32-34-8F-22 wilson 2 BC-D0-34-85-67-2F-05-4D-B5-77-E3-F4-AD-51-45-02
//84-E8-E5-9A-6B-56-E2-45-9A-87-54-D1-78-6B-D3-56 porschev 2 58-D6-C4-32-6A-A1-99-48-A4-8B-C8-5D-BC-C9-3E-17
DirectorySearcher.Filter屬性擴(kuò)充說明 |
DirectorySearcher mySearcher = new DirectorySearcher(entryOU, "(objectclass=organizationalUnit)"); //查詢組織單位
第二個(gè)參數(shù)是一個(gè)filter,也可以根據(jù)需求輸入其它篩選條件,下面列出幾個(gè)常用的
篩選條件 |
值 |
用戶 |
(&(objectCategory=person)(objectClass=user)) |
計(jì)算機(jī) |
(objectCategory=computer) |
組 |
(objectCategory=group) |
聯(lián)系人 |
(objectCategory=contact) |
共享文件夾 |
(objectCategory=volume) |
打印機(jī) |
(objectCategory=printQueue) |
更多高級(jí)篩選請(qǐng)查看:http://msdn.microsoft.com/zh-cn/library/system.directoryservices.directorysearcher.filter(v=vs.80).aspx
用戶屬性擴(kuò)充說明(含圖文屬性對(duì)照) |
示例中只對(duì)用戶進(jìn)行了讀取了幾個(gè)屬性,用過AD域的應(yīng)該都知道,用戶的屬性較多也比較常用。
下面通過AD域的用戶詳細(xì)信來對(duì)照一下相應(yīng)的屬性名

對(duì)應(yīng)編號(hào) |
選項(xiàng)卡對(duì)應(yīng)項(xiàng)名 |
屬性名 |
① |
姓(L) |
sn |
② |
名(F) |
givenName |
③ |
顯示名稱(S) |
displayName |
④ |
描述(D) |
description |
⑤ |
辦公室(C) |
physicalDeliveryOfficeName |
⑥ |
英文縮寫(I) |
initials |
⑦ |
電話號(hào)碼(T) |
telephoneNumber |
⑧ |
電子郵件(M) |
mail |
⑨ |
網(wǎng)頁(yè)(W) |
wWWHomePage |
⑩ |
電話號(hào)碼-其它(O)... |
otherTelephone |
|
網(wǎng)頁(yè)-其它(R)... |
url |

對(duì)應(yīng)編號(hào) |
選項(xiàng)卡對(duì)應(yīng)項(xiàng)名 |
屬性名 |
① |
國(guó)家/地區(qū)(O) |
co |
② |
省/自治區(qū)(V) |
st |
③ |
市/縣(C) |
l |
④ |
街道(S) |
streetAddress |
⑤ |
郵政信箱(B) |
postOfficeBox |
⑥ |
郵政編碼(Z) |
postalCode |

對(duì)應(yīng)編號(hào) |
選項(xiàng)卡對(duì)應(yīng)項(xiàng)名 |
屬性名 |
① |
用戶登錄名(U) |
userPrincipalName |
② |
用戶登錄名(Windows 2000 以前版本)(W) |
sAMAccountName |

對(duì)應(yīng)編號(hào) |
選項(xiàng)卡對(duì)應(yīng)項(xiàng)名 |
屬性名 |
① |
家庭電話(M) |
homePhone |
② |
尋呼機(jī)(P) |
pager |
③ |
移動(dòng)電話(B) |
mobile |
④ |
傳真(F) |
facsimileTelephoneNumber |
⑤ |
IP電話(I) |
ipPhone |
⑥ |
注釋 |
info |
⑦ |
家庭電話-其它(O) |
otherHomePhone |
⑧ |
尋呼機(jī)-其它(T) |
otherPager |
⑨ |
移動(dòng)電話-其它(B) |
otherMobile |
⑩ |
傳真-其它(E) |
otherFacsimileTelephoneNumber |
|
IP電話-其它(R) |
otherIpPhone |

對(duì)應(yīng)編號(hào) |
選項(xiàng)卡對(duì)應(yīng)項(xiàng)名 |
屬性名 |
① |
公司(C) |
company |
② |
部門(D) |
department |
③ |
職務(wù)(J) |
title |
④ |
經(jīng)理-姓名(N) |
manager |
⑥ |
直接下屬(E) |
directReports |
還有一些屬性沒有列出來,可以循環(huán)輸出DirectoryEntry.Properties.PropertyNames來找
比如用objectsid這也是個(gè)用戶比較重要的屬性,在設(shè)置Windows共享時(shí)會(huì)用到!
示例下載:http://files.cnblogs.com/zhongweiv/SynchronousAD.zip
示例代碼,寫得比較簡(jiǎn)陋,有需要就下載了將就著看一下吧^_^!