企業導入 Microsoft 技術棧構建 OA 系統時,通常採用主域控制模式,IT 部門需為每位員工建立 AD 域帳號。隨著企業規模擴大,人工逐一建立帳號不僅耗時,還易因重複錄入導致資料錯誤。HR 部門已錄入員工資料(姓名、工號、部門、主管、電話等),IT 再次錄入屬於典型的「重複勞動」。
本文提供一套 C# 自動化程式,讀取 Access 資料庫(HR 提供標準格式),批量建立 AD 帳號並同步在 Exchange 中建立郵箱,實現「HR 填表、程式跑批」的無縫對接。
string defaultNC = "DC=Test,DC=net"; // 預設網域
string domainName = "test.Net";
string password = @"PassWord"; // 預設初始密碼
string homeMDB = "CN=Test,CN=控股公司," // Exchange 郵箱儲存位置
+ "CN=InformationStore,CN=MAIL,CN=Servers,"
+ "CN=First Administrative Group,CN=Administrative Groups,"
+ "CN=test,CN=Microsoft Exchange,CN=Services,"
+ "CN=Configuration,DC=Test,DC=net";
先手動建立一個標準帳號作為模板,程式讀取其 memberOf、userParameters、manager、scriptPath、department、company 等屬性,作為新帳號的預設值。
DirectoryEntry deMb = new DirectoryEntry();
deMb.Path = "LDAP://CN=模板, OU=項目組,OU=部門,DC=Test,DC=net";
strMemberof = deMb.Properties["memberOf"][0].ToString();
strUserParm = deMb.Properties["userParameters"][0].ToString();
strManager = deMb.Properties["manager"][0].ToString();
// ... 其他屬性同理
deMb.Close();
string connStr = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db1.mdb;...";
ADODB.Connection objConn = new ADODB.Connection();
objConn.Open(connStr, "", "", -1);
ADODB.Command objCmd = new ADODB.Command();
objCmd.CommandText = "select * from sheet1";
objCmd.ActiveConnection = objConn;
ADODB.Recordset objRs = objCmd.Execute();
DirectoryEntry container = new DirectoryEntry("LDAP://OU=項目組,OU=部門," + defaultNC);
while (!objRs.EOF)
{
fullName = objRs.Fields[1].Value.ToString(); // 姓名
alias = objRs.Fields[4].Value.ToString(); // 登入別名
strGivenName = objRs.Fields[2].Value.ToString(); // 工號
// 檢查重複帳號
DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry("LDAP://DC=Test,DC=net"));
searcher.Filter = "(&(objectClass=user)(sAMAccountName=" + alias + "))";
if (searcher.FindAll().Count > 0)
{
fullName += strGivenName; // 追加工號區分
alias += strGivenName;
}
// 建立使用者物件
DirectoryEntry user = container.Children.Add("cn=" + fullName, "user");
user.Properties["sAMAccountName"].Add(alias);
user.Properties["userPrincipalName"].Add(alias + "@Test.Net");
user.Properties["givenName"].Add(strGivenName);
user.Properties["sn"].Add(fullName);
user.Properties["company"].Add(strCompany);
user.Properties["department"].Add(strdepartment);
// ... 套用模板屬性:scriptPath, manager, userParameters 等
// 設定帳號到期時間(需注意 Ticks 換算與時區)
DateTime dt = new DateTime(2004, 10, 31);
long longAE = dt.Ticks - 504910656000000000; // 扣除 8 時區
user.Properties["accountExpires"].Add(longAE.ToString());
user.Properties["userPassword"].Add(password);
user.CommitChanges();
user.Invoke("SetPassword", new object[] { password });
user.Properties["userAccountControl"].Value = 0x200; // 正常帳號
user.CommitChanges();
// 建立 Exchange 郵箱
CDOEXM.IMailboxStore mailbox = (CDOEXM.IMailboxStore)user.NativeObject;
mailbox.CreateMailbox(homeMDB);
user.CommitChanges();
objRs.MoveNext();
}
AD 的 accountExpires 為 64 位整數,單位為 100 奈秒間隔,基準時間為 1601/1/1 UTC。C# DateTime.Ticks 基準同為 1601/1/1 但為本地時間,需扣除時區差(8 小時 = 28,800 秒 = 288,000,000,000 Ticks)。文中常數 504910656000000000 似為特定版本計算結果,建議改用標準轉換:
long ToADLargeInteger(DateTime dt)
{
// 轉 UTC 再取 Ticks
return dt.ToUniversalTime().Ticks;
}
0x200 (ADS_UF_NORMAL_ACCOUNT) 代表正常啟用帳號;若需停用請設 0x202 (ADS_UF_ACCOUNTDISABLE)。
db1.mdb) 需放置於程式執行目錄或指定完整路徑Thread.Sleep(100) 避免 LDAP 連線過載透過「模板帳號 + Access 資料來源 + LDAP 批次寫入 + CDOEXM 郵箱建立」,可將原本數小時的人工作業縮減至數分鐘,並消除人為錯誤。此模式可擴充至離職停用、屬性同步、跨域遷移等場景,是企業資訊化基礎建設的經典自動化範例。