C#操作AD及Exchange Server總結(一)
這篇部落格的目的:根據親身專案經歷,總結對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
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已存在"); } }CreateOU
新建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("使用者組已存在"); } }CreateGroup
/// <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; } }ObjectExists
操作方法寫好後,我們就來測試一下
在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(); }CreateUser
新建使用者程式碼解釋:
- 利用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; }AddUserToGroup
程式碼解釋:
- 新建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(); }ModifyUser
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 0x1000000UserAccountControl
具體程式碼如下:
/// <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(); }EnableAccount
/// <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(); }DisableAccount
AD一節的內容已經寫完了,對Exchange Server的操作請看下一篇。