Active Directory (AD) 採用階層結構:網域 (Domain) → 組織單位 (OU) → 用戶/群組/電腦。所有用戶最終都隸屬於 Users 容器下的 Domain Users 群組。
權限關鍵:
程式碼中需使用域管理員憑證建立 DirectoryEntry 才能執行寫入操作。
using System.DirectoryServices;
public void SearchUser(string domainName, string adminUser, string adminPassword)
{
// 1. 取得 Domain Users 群組成員
string groupPath = $"WinNT://{domainName}/Domain Users,group";
using (DirectoryEntry group = new DirectoryEntry(groupPath, adminUser, adminPassword))
{
foreach (object member in (IEnumerable)group.Invoke("Members"))
{
using (DirectoryEntry userEntry = new DirectoryEntry(member))
{
string samAccountName = userEntry.Name;
// 2. 使用 LDAP 過濾器精確查找
string ldapPath = $"LDAP://{domainName}";
string filter = $"(sAMAccountName={samAccountName})";
using (DirectorySearcher searcher = new DirectorySearcher(ldapPath) { Filter = filter })
{
SearchResult result = searcher.FindOne();
if (result != null)
{
using (DirectoryEntry user = result.GetDirectoryEntry())
{
// 3. 以管理員身分讀取完整屬性
string ouPath = user.Parent.Path;
using (DirectoryEntry ouEntry = new DirectoryEntry(ouPath, adminUser, adminPassword))
{
foreach (DirectoryEntry child in ouEntry.Children)
{
if (child.SchemaClassName == "user" &&
child.Properties["sAMAccountName"].Value?.ToString().ToLower() == samAccountName.ToLower())
{
foreach (string propName in child.Properties.PropertyNames)
{
object val = child.Properties[propName][0];
Console.WriteLine($"{propName}: {val}");
}
break;
}
}
}
}
}
}
}
}
}
}
public void AddUser(string ouLdapPath, string username, string chineseName, string adminUser, string adminPassword)
{
try
{
using (DirectoryEntry ouEntry = new DirectoryEntry(ouLdapPath, adminUser, adminPassword))
using (DirectoryEntry newUser = ouEntry.Children.Add($"CN={chineseName}", "user"))
{
newUser.Properties["userPrincipalName"].Value = username;
newUser.Properties["name"].Value = chineseName;
newUser.Properties["sAMAccountName"].Value = username;
// 66048 = NORMAL_ACCOUNT (512) + DONT_EXPIRE_PASSWD (65536)
newUser.Properties["userAccountControl"].Value = 66048;
newUser.CommitChanges();
Console.WriteLine($"用戶 {username} 建立成功");
}
}
catch (Exception ex)
{
Console.WriteLine($"建立用戶失敗: {ex.Message}");
}
}
public void AddOU(string parentOuLdapPath, string ouName, string adminUser, string adminPassword)
{
try
{
using (DirectoryEntry parent = new DirectoryEntry(parentOuLdapPath, adminUser, adminPassword))
using (DirectoryEntry newOu = parent.Children.Add($"OU={ouName}", "organizationalUnit"))
{
newOu.Properties["name"].Value = ouName;
newOu.Properties["instanceType"].Value = 4;
newOu.Properties["ou"].Value = ouName;
// 選填屬性
newOu.Properties["postalCode"].Value = "777";
newOu.CommitChanges();
Console.WriteLine($"OU {ouName} 建立成功");
}
}
catch (Exception ex)
{
Console.WriteLine($"建立 OU 失敗: {ex.Message}");
}
}
public void ModifyUser(string domainName, string samAccountName, string propertyName, string newValue, string adminUser, string adminPassword)
{
try
{
string filter = $"(sAMAccountName={samAccountName})";
using (DirectorySearcher searcher = new DirectorySearcher($"LDAP://{domainName}") { Filter = filter })
{
SearchResult result = searcher.FindOne();
if (result != null)
{
string ouPath = result.GetDirectoryEntry().Parent.Path;
using (DirectoryEntry ouEntry = new DirectoryEntry(ouPath, adminUser, adminPassword))
{
foreach (DirectoryEntry user in ouEntry.Children)
{
if (user.SchemaClassName == "user" &&
user.Properties["sAMAccountName"].Value?.ToString().ToLower() == samAccountName.ToLower())
{
user.Properties[propertyName].Value = newValue;
user.CommitChanges();
Console.WriteLine($"用戶 {samAccountName} 的 {propertyName} 已更新為 {newValue}");
break;
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"修改失敗: {ex.Message}");
}
}
public void DeleteObject(string ldapPath, string adminUser, string adminPassword)
{
try
{
using (DirectoryEntry obj = new DirectoryEntry(ldapPath, adminUser, adminPassword))
using (DirectoryEntry parent = obj.Parent)
{
parent.Children.Remove(obj);
Console.WriteLine($"物件 {ldapPath} 已刪除");
}
}
catch (Exception ex)
{
Console.WriteLine($"刪除失敗: {ex.Message}");
}
}
DirectoryEntry/DirectorySearcher 正確釋放非託管資源LDAP://OU=部門,OU=分公司,DC=domain,DC=com,層級由下而上sAMAccountName)searcher.PageSize = 1000 避免伺服器限制DirectoryServicesCOMException 可取得詳細錯誤碼