這篇博客的目的:根據親身項目經歷,總結對AD及Exchange Server的操作,包括新建AD用戶,設置密碼,為AD用戶創建郵箱等。
本文完全原創,轉載請說明出處,希望對大家有用。
文檔目錄:
- 測試環境及需求簡述
- 對AD操作
- 引入DLL及方法簡述
- 新增OU或Security Group
- 新建AD User
- 添加用戶到組或從組中刪除用戶
- 用戶信息更新
- Enable/Disable用戶賬號
- 對Exchange Server操作
- 為AD用戶新建郵箱
- 配置客戶端和服務器
- 總結歸納
一、測試環境及需求簡述
1、測試環境
服務器:windows server 2008R2
Exchange:Exchange Server 2010 sp1
開發工具:Visual Studio 2010
一台exchange服務器+一台AD服務器+一台承載測試程序的服務器
2、需求簡述
- 根據提供的信息創建對應的OU
- 根據提供的用戶信息新建AD用戶
- 根據提供的信息修改AD用戶
- 為AD用戶
二、AD操作
1、引入DLL及方法簡述
MS提供了遠程操作AD的DLL:System.DirectoryServices(添加引用中有);
其中,我們使用LDAP協議訪問AD,LDAP翻譯為輕量目錄訪問協議。
在使用的時候,需要注意一些問題:
- 如果在WEB應用中使用,在數據量大的時候回產生超時的問題,建議采取其他方式如MS MQ等方式處理信息,避免超時的問題。
- 使用LDAP會有安全風險,畢竟通過網絡傳輸用戶憑證並不是很安全,最好是運行在企業內網。
DirectoryServices其實提供了其他很多操作,如對IIS的操作,對本地用戶的操作,有興趣的可以了解下。
2、新增OU或Security Group
首先新建一個控制台應用程序
添加服務引用:
在項目中新建一個ADHelper.cs用來提供AD操作的公用方法
public class ADHelper { /// <summary> /// 創建連接 /// </summary> /// <returns></returns> public static DirectoryEntry GetDirectoryEntry() { DirectoryEntry de = new DirectoryEntry(); de.Path = "LDAP://AD服務器地址/OU=CompanyA,DC=contoso,DC=com"; de.Username = @"contoso\管理員賬號"; de.Password = "管理員密碼"; return de; } /// <summary> /// 帶有一個參數的創建連接重載 /// </summary> /// <param name="DomainReference"></param> /// <returns></returns> public static DirectoryEntry GetDirectoryEntry(string DomainReference) { DirectoryEntry entry = new DirectoryEntry(DomainReference, "管理員賬號", "管理員密碼", AuthenticationTypes.Secure); return entry; } }
ADHelper代碼解釋:
- 新建一個DirectoryEntry類,也就是活動目錄的入口類
- 指定要連接到的Path,在稍后的新建OU實例中會詳細解釋Path的組成
- 用來連接AD的管理員賬號,此管理員賬號必須有操作AD的權限
- 管理員的密碼,同樣是為了連接AD
- 重載的GetDirectoryEntry是為了根據輸入的路徑引用此路徑的入口,稍后會用到
新建一個ADManage.cs操作類,用來定義具體的操作方法:
/// <summary> /// 新建OU /// </summary> /// <param name="path"></param> public void CreateOU(string name) { if (!ObjectExists(name, "OU")) { DirectoryEntry dse = ADHelper.GetDirectoryEntry(); DirectoryEntries ous = dse.Children; DirectoryEntry newou = ous.Add("OU=" + name, "OrganizationalUnit"); newou.CommitChanges(); newou.Close(); dse.Close(); } else { Console.WriteLine("OU已存在"); } }
新建OU代碼解釋:
- ObjectExists方法判斷新增的OU是否已經存在,代碼下面會附上
- 利用ADHelper生成目錄入口,本例是在一個測試的CompanyA OU中
- Children屬性獲取所有子項,並使用Add方法添加OU
- 提交更改,發回服務器
/// <summary> /// 新建Security Group /// </summary> /// <param name="path"></param> public void CreateGroup(string name) { if (!ObjectExists(name, "Group")) { DirectoryEntry dse = ADHelper.GetDirectoryEntry(); DirectoryEntries Groups = dse.Children; DirectoryEntry newgroup = Groups.Add("CN=" + name, "group"); newgroup.CommitChanges(); newgroup.Close(); dse.Close(); } else { Console.WriteLine("用戶組已存在"); } }
/// <summary> /// 判斷是否存在 /// </summary> /// <param name="objectName"></param> /// <param name="catalog"></param> /// <returns></returns> public bool ObjectExists(string objectName, string catalog) { DirectoryEntry de = ADHelper.GetDirectoryEntry(); DirectorySearcher deSearch = new DirectorySearcher(); deSearch.SearchRoot = de; switch (catalog) { case "User": deSearch.Filter = "(&(objectClass=user) (cn=" + objectName + "))"; break; case "Group": deSearch.Filter = "(&(objectClass=group) (cn=" + objectName + "))"; break; case "OU": deSearch.Filter = "(&(objectClass=OrganizationalUnit) (OU=" + objectName + "))"; break; default: break; } SearchResultCollection results = deSearch.FindAll(); if (results.Count == 0) { return false; } else { return true; } }
操作方法寫好后,我們就來測試一下
在Program中寫測試代碼:
static void Main(string[] args) { ADManage manage=new ADManage(); //Test create ou Console.WriteLine("Create OU Start..."); try { manage.CreateOU("NewOU01"); Console.WriteLine("Create OU Finish..."); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("Create OU Error..."); Console.WriteLine(ex); Console.ReadLine(); } //Test create group Console.WriteLine("Create Group Start..."); try { manage.CreateGroup("NewGroup01"); Console.WriteLine("Create Group Finish..."); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("Create Group Error..."); Console.WriteLine(ex); Console.ReadLine(); } }
運行代碼

域控中查看結果:
補充:
如何在多層OU下創建新的OU?
OU類似於文件夾,在不同的目錄中可以有相同名字的OU,想要在多層OU下創建OU,首先要確認路徑Path
假設有一個OU,path為:
CompanyA
BranchB
DepartmentC
則GetDirectoryEntry實例中的path屬性應該修改為:
“LDAP://AD服務器地址/OU=DepartmentC,OU=BranchB,OU=CompanyA,DC=contoso,DC=com”,這樣新建的OU就會在DepartmentC目錄下。
3、新建AD User
新建User與新建OU或組有一些不同,先看代碼:
/// <summary> /// 新建用戶 /// </summary> /// <param name="name"></param> /// <param name="login"></param> public void CreateUser(string name, string login) { if (ObjectExists(login, "User")) { Console.WriteLine("用戶已存在"); Console.ReadLine(); return; } DirectoryEntry de = ADHelper.GetDirectoryEntry(); DirectoryEntries users = de.Children; DirectoryEntry newuser = users.Add("CN=" + login, "user"); SetProperty(newuser, "givenname", name); SetProperty(newuser, "SAMAccountName", login); SetProperty(newuser, "userPrincipalName", login + "@contoso.com"); newuser.CommitChanges(); SetPassword(newuser.Path); newuser.CommitChanges(); newuser.Close(); de.Close(); } /// <summary> /// 屬性設置 /// </summary> /// <param name="de"></param> /// <param name="PropertyName"></param> /// <param name="PropertyValue"></param> public static void SetProperty(DirectoryEntry de, string PropertyName, string PropertyValue) { if (PropertyValue != null) { if (de.Properties.Contains(PropertyName)) { de.Properties[PropertyName][0] = PropertyValue; } else { de.Properties[PropertyName].Add(PropertyValue); } } } /// <summary> /// 密碼設置 /// </summary> /// <param name="path"></param> public void SetPassword(string path) { DirectoryEntry user = new DirectoryEntry(); user.Path = path; user.AuthenticationType = AuthenticationTypes.Secure; object ret = user.Invoke("SetPassword",new object[] {"Password01!"}); user.CommitChanges(); user.Close(); }
新建用戶代碼解釋:
- 利用ObjectExists判斷用戶是否存在,如果存在則提示用戶已存在
- 新建入口類實例,Add方法新增用戶
- SetProperty設置新用戶的屬性(顯示名、Pre-Windows 2000登錄名、登錄名),並提交更改
- SetPassword設置用戶初始密碼,提交更改,關閉連接
編寫測試代碼:
static void Main(string[] args) { ADManage manage=new ADManage(); Console.WriteLine("Create User Start..."); try { manage.CreateUser("Employee John", "Employee01"); Console.WriteLine("Create User Finish..."); Console.ReadLine(); } catch (System.DirectoryServices.DirectoryServicesCOMException ex) { Console.WriteLine("Create User Error..."); Console.WriteLine(ex); Console.ReadLine(); } }
測試結果:

注意:此時新建的賬戶是停用狀態,后面的章節會介紹如何啟用/停用
4、添加用戶到組或從組中刪除用戶
在組中添加/刪除用戶使用到DirectorySearcher,用來查找組,見代碼:
/// <summary> /// 添加用戶到組 /// </summary> /// <param name="de"></param> /// <param name="userDn"></param> /// <param name="GroupName"></param> public void AddUserToGroup(DirectoryEntry de, string userDn, string GroupName) { DirectorySearcher deSearch = new DirectorySearcher(); deSearch.SearchRoot = de; deSearch.Filter = "(&(objectClass=group) (cn=" + GroupName + "))"; SearchResult Groupresult = deSearch.FindOne(); if (Groupresult != null) { DirectoryEntry user = ADHelper.GetDirectoryEntry("LDAP://AD服務器/" + userDn); if (user != null) { DirectoryEntry dirEntry = Groupresult.GetDirectoryEntry(); if (dirEntry.Properties["member"].Contains(userDn)) { Console.WriteLine("用戶組中已存在該用戶,即將移除"); dirEntry.Properties["member"].Remove(userDn); Console.WriteLine("用戶已從組中移除"); } else { dirEntry.Properties["member"].Add(userDn); Console.WriteLine("添加成功,用戶已添加到組"); } dirEntry.CommitChanges(); dirEntry.Close(); } else { Console.WriteLine("用戶不存在"); } user.Close(); } else { Console.WriteLine("用戶組不存在"); } return; }
代碼解釋:
- 新建DirectorySearcher實例,為Filter賦值,根據傳入的參數de目錄查找該安全組(注意:此組需要包含在DirectoryEntry中)
- 根據參數userDn判斷用戶是否存在(userDn是用戶的標識名如:“CN=Employee01,OU=CompanyA,DC=rzh,DC=com”)
- dirEntry.Properties["member"].Contains(userDn)判斷組中是否存在該用戶
- 如果該組不存在該用戶,則添加用戶到組。如果該組中存在該用戶,則將該用戶從組中移除
測試一下,這里只測試添加,移除操作請自行測試:
class Program { static void Main(string[] args) { ADManage manage=new ADManage(); Console.WriteLine("Add user to group Start..."); try { manage.AddUserToGroup(ADHelper.GetDirectoryEntry(), "CN=Employee01,OU=CompanyA,DC=contoso,DC=com", "NewGroup01"); Console.WriteLine("Add user to group Finish..."); Console.ReadLine(); } catch (System.DirectoryServices.DirectoryServicesCOMException ex) { Console.WriteLine("Add user to group Error..."); Console.WriteLine(ex); Console.ReadLine(); } } }
測試結果:
5、用戶信息更新
用戶信息更新也比較簡單,直接上示例代碼+測試代碼,如果有疑問,隨時聯系:
public void ModifyUser(DirectoryEntry de,string UserName,string company) { DirectorySearcher deSearch = new DirectorySearcher(); deSearch.SearchRoot = de; deSearch.Filter = "(&(objectClass=user) (cn=" + UserName + "))"; SearchResult result = deSearch.FindOne(); if (result != null) { DirectoryEntry dey = ADHelper.GetDirectoryEntry(result.Path); SetProperty(dey, "company", company); dey.CommitChanges(); dey.Close(); } de.Close(); }
static void Main(string[] args) { ADManage manage=new ADManage(); Console.WriteLine("Modify user info Start..."); try { manage.ModifyUser(ADHelper.GetDirectoryEntry(), "Employee01", "CompanyA"); Console.WriteLine("Modify user info Finish..."); Console.ReadLine(); } catch (System.DirectoryServices.DirectoryServicesCOMException ex) { Console.WriteLine("Modify user info Error..."); Console.WriteLine(ex); Console.ReadLine(); } }
6、Enable/Disable用戶賬號
Enable/Disable用戶賬號用到了新的屬性userAccountControl,可以對賬號密碼的是否過期,賬號是否可用等進行設置。
以下是設置userAccountControl時會用到值
SCRIPT 0x0001 ACCOUNTDISABLE 0x0002 HOMEDIR_REQUIRED 0x0008 LOCKOUT 0x0010 PASSWD_NOTREQD 0x0020 PASSWD_CANT_CHANGE 0x0040 ENCRYPTED_TEXT_PWD_ALLOWED 0x0080 TEMP_DUPLICATE_ACCOUNT 0x0100 NORMAL_ACCOUNT 0x0200 INTERDOMAIN_TRUST_ACCOUNT 0x0800 WORKSTATION_TRUST_ACCOUNT 0x1000 SERVER_TRUST_ACCOUNT 0x2000 DONT_EXPIRE_PASSWORD 0x10000 MNS_LOGON_ACCOUNT 0x20000 SMARTCARD_REQUIRED 0x40000 TRUSTED_FOR_DELEGATION 0x80000 NOT_DELEGATED 0x100000 USE_DES_KEY_ONLY 0x200000 DONT_REQ_PREAUTH 0x400000 PASSWORD_EXPIRED 0x800000 TRUSTED_TO_AUTH_FOR_DELEGATION 0x1000000
具體代碼如下:
/// <summary> /// 啟用賬號 /// </summary> /// <param name="de"></param> public void EnableAccount(DirectoryEntry de) { //設置賬號密碼不過期 int exp = (int)de.Properties["userAccountControl"].Value; de.Properties["userAccountControl"].Value = exp | 0x10000; de.CommitChanges(); //啟用賬號 int val = (int)de.Properties["userAccountControl"].Value; de.Properties["userAccountControl"].Value = val & ~0x0002; de.CommitChanges(); }
/// <summary> /// 停用賬號 /// </summary> /// <param name="de"></param> public void DisableAccount(DirectoryEntry de) { //啟用賬號 int val = (int)de.Properties["userAccountControl"].Value; de.Properties["userAccountControl"].Value = val | 0x0002; de.CommitChanges(); }
AD一節的內容已經寫完了,對Exchange Server的操作請看下一篇。
如果有什么疑問,請及時與我討論
