Ative Directory
▌背景
最近在寫和Active Directory相關的程式,感覺對於操控LDAP結構的程式碼如果沒有分層,真的是很難閱讀啊! 所以整理一下在後端上的寫法。
▌環境
l Windows 7 Enterprise
l Visual Studio 2015 Ent.
▌實作
在開發AD相關程式前,最重要的是必須先取得AD Domain的名稱,
可直接在Command line下以下指令查詢:
wmic
computersystem get domain
|
另一個方式是開啟Acive Director管理工具查看。
備註1. 在AD LDAP下的資料夾,我們稱之為OU (Organization Unit)。
備註2. OU及其內的使用者或群組, 都是一個單位:Directory Entry
備註3. 每個Directory Entry都會有一個代表它自己的LDAP Path (路徑)。
▋Service Layer : HOW
will we get information from AD
我選擇將一些基礎查詢的服務加進來服務層,定義”如何”查詢, 主要方法有以下:
l 以網域名稱註冊一個AD服務
l 指定LDAP Path,並取得底下所有符合篩條件的Directory Entry
l 指定Directory Entry,並取得底下所有符合篩條件的子節點 (Sub Directory Entries)
l 取得一個Directory Entry的所有屬性。
public class ActiveDirectoryService : IDisposable
{
/// <summary>
/// 判斷AD Domain是否存在,並回傳一個對應的ActiveDirectory.Domain物件。 若沒有設定Domain Id則以本機所在的AD網域為主
/// </summary>
/// <param name="domainId">網域</param>
/// <param name="domain">out
ActiveDirectory.Domain</param>
/// <returns>true(OK)/false(無此AD網域)</returns>
public bool RegisterDirectoryService(
string domainId, out
System.DirectoryServices.ActiveDirectory.Domain domain)
{
if (String.IsNullOrEmpty(domainId))
{
domain = Domain.GetCurrentDomain();
return true;
}
else
{
domain = null;
DirectoryContext context = new
DirectoryContext(DirectoryContextType.Domain,
domainId);
trys
{
domain =
System.DirectoryServices.ActiveDirectory.Domain.GetDomain(
context);
return true;
}
catch (Exception)
{
return false;
}
}
}
/// <summary>
/// 取得LDAP路徑下所有符合條件的子節點
/// </summary>
/// <param name="dirPath">LDAP目錄</param>
/// <param name="filterForDirectorySearcher">Filter條件</param>
/// <returns>DirectoryEntry集合</returns>
public IEnumerable<DirectoryEntry>
GetDirectoryEntries(String dirPath, String filterForDirectorySearcher)
{
var dir = new DirectoryEntry(dirPath);
return this.GetDirectoryEntries(dir,
filterForDirectorySearcher);
}
/// <summary>
/// 取得該節點下所有符合條件的子節點
/// </summary>
/// <param name="dir">LDAP目錄</param>
/// <param name="filterForDirectorySearcher">Filter條件</param>
/// <returns>DirectoryEntry集合</returns>
public IEnumerable<DirectoryEntry>
GetDirectoryEntries(DirectoryEntry dir, String filterForDirectorySearcher)
{
//create the return object
//var rtnDirectoryEntries = new
List<DirectoryEntry>();
//create instance fo the direcory
searcher
DirectorySearcher deSearch = new DirectorySearcher(dir);
//set the search filter
deSearch.Filter =
filterForDirectorySearcher;
SearchResultCollection results =
deSearch.FindAll();
deSearch.SearchScope = SearchScope.Subtree; //預設搜尋所有子節點
//if found then return, otherwise
return Null
if (results != null &&
results.Count > 0)
{
foreach (SearchResult rslt in results)
{
yield return rslt.GetDirectoryEntry();
}
}
}
/// <summary>
/// 取得在指定DirectoryEntry下的Properties
/// </summary>
/// <param name="dir">DirectoryEntry</param>
/// <param name="constraints">指定屬性名稱</param>
/// <returns>KeyValuePair
Emerable</returns>
public IEnumerable<KeyValuePair<String, object>>
GetDirectoryEntryProperties(DirectoryEntry de, String[] constraints = null)
{
if (de.Properties != null &&
de.Properties.Count > 0)
{
foreach (string property in de.Properties.PropertyNames)
{
if (constraints == null ||
constraints.Any(x => x.Equals(property, StringComparison.OrdinalIgnoreCase)))
{
yield return new KeyValuePair<string, object>(property,
de.Properties[property][0]);
}
}
}
}
public void Dispose()
{
}
}
|
▋Repository : WHAT information
will we get from AD
在Repository,我們可以決定要找那些資訊,以此範例的目的為列出所有AD User的資訊, 所以我們需要:
1. 尋找所有OU
2. 列出在一個OU下的所有Users
public class ActiveDirectoryRepository : IDisposable
{
private ActiveDirectoryService _adService = null;
System.DirectoryServices.ActiveDirectory.Domain _adDomain = null;
public ActiveDirectoryRepository(String domainId)
{
this._adService = new ActiveDirectoryService();
this._adService.RegisterDirectoryService(domainId, out this._adDomain);
}
public IEnumerable<DirectoryEntry> GetAllOU()
{
String filter = "(objectCategory=organizationalUnit)";
return this._adService.GetDirectoryEntries(
this._adDomain.GetDirectoryEntry(),
filter);
}
public IEnumerable<DirectoryEntry>
GetUserDirectoryEntriers(DirectoryEntry de)
{
String filter = "(objectCategory=user)";
return this._adService.GetDirectoryEntries(de,
filter);
}
public IEnumerable<KeyValuePair<String, object>>
GetDirectoryEntryProperties(DirectoryEntry de, String[] constraints = null)
{
return this._adService.GetDirectoryEntryProperties(de,
constraints);
}
public void Dispose()
{
this._adService.Dispose();
this._adService = null;
this._adDomain = null;
}
}
|
▋主程式
切完階層之後,主程式可專注於在流程上即可。
底下程式碼將列出所有AD User的資訊~
String domainId = "XXXXX.com";
using (var adOURepository = new ActiveDirectoryRepository(domainId))
{
#region Get All OU
var ouDirectoryEntries = adOURepository.GetAllOU();
#endregion
#region In each OU, get all the USERs inside
foreach (var ouDirectoryEntry in ouDirectoryEntries)
{
var userDirectoryEntries =
adOURepository.GetUserDirectoryEntriers(ouDirectoryEntry);
if (userDirectoryEntries != null)
{
#region output an user's information
foreach (var de in userDirectoryEntries)
{
Debug.WriteLine(de.Path);
var propertiesContainer =
adOURepository.GetDirectoryEntryProperties(de);
propertiesContainer.Each(
x => Debug.WriteLine(
x.Key + "("+
x.Value.GetType() +") : " + x.Value));
}
#endregion
}
}
|
▌Reference
沒有留言:
張貼留言