System.DirectoryServices.dll を参照設定すると LDAP (Lightweight Directory Access Protocol) による Active Directory 検索ができるようになります。やってみたらそれほど難しくはありませんでした。
ユーザーの検索をしてみる
example.com ドメインに対してユーザーログオン名 (userPrincipalName) で検索してみます。DirectoryEntry クラスは Active Directory のオブジェクトをカプセル化します。DirectorySearcher クラスでクエリ式を作成します。
public static class Program { private static void Main(string[] args) { // 検索するルート階層を指定する using (var entry = new DirectoryEntry("LDAP://example.com/CN=Users,DC=example,DC=com")) using (var searcher = new DirectorySearcher(entry)) { // ユーザーログオン名が hoge@example.com のユーザーを検索する searcher.Filter = "(userPrincipalName=hoge@example.com)"; // 1 件だけ抽出するときは FindOne メソッドで // 結果が複数件戻ってくるときは FindAll メソッドを使う var result = searcher.FindOne(); foreach (var value in result.GetDirectoryEntry().Properties .Cast<PropertyValueCollection>() .OrderBy(x => x.PropertyName)) { // 属性と値をすべて表示する Console.WriteLine("{0}={1}", value.PropertyName, string.Join(";", value.Cast<object>().Select(x => x.ToString()))); } } Console.ReadKey(); } }
LDAP クエリは書き方が特殊で、and 条件は (&(A=b)(B=b)) のように書き、or 条件は (|(A=a)(B=b)) のように書きます。慣れてしまえばそれほどは難しくありません。ワイルドカードも使えますので、ある程度自由の利いた検索ができるようになっています。
FindOne メソッドの戻り値は SearchResult クラスです。GetDirectoryEntry メソッドを呼び出せば DirectoryEntry クラスのオブジェクトが取得できるので、属性を取得したり、さらに別の検索をすることができます。ちなみに Active Directory の属性は単一の値を返すものと複数の値を返すものがあるので、PropertyValueCollection クラスには Value プロパティと Items プロパティの 2 種類の方法が用意されています。今回は LINQ でぶん回して複数の値を string.Join するようにしています。
ユーザーが属するグループの検索をしてみる
ちょっとだけ応用編。検索したユーザーが所属するグループを検索します。グループの member 属性には識別名が入っているのでユーザーの distinguishedName 属性の値を渡してあげます。今度は結果が複数あるので FindAll メソッドを使っています。LINQ には対応していないので Cast したり Select しなければいけないのは御愛嬌ということで。
public static class Program { private static void Main(string[] args) { using (var entry = new DirectoryEntry("LDAP://example.com/CN=Users,DC=domain,DC=local")) using (var searcher = new DirectorySearcher(entry)) { searcher.Filter = "(userPrincipalName=hoge@example.com)"; var result = searcher.FindOne(); var user = result.GetDirectoryEntry(); // 識別名を取得する var distinguishedName = user.Properties["distinguishedName"].Value; // メンバーにユーザーが含まれるグループを検索する searcher.Filter = string.Format("(&(objectClass=group)(member={0}))", distinguishedName); var groups = searcher.FindAll(); foreach (var group in groups.Cast<SearchResult>().Select(x => x.GetDirectoryEntry())) { Console.WriteLine(group.Properties["cn"].Value); } } Console.ReadKey(); } }
もちろん Exchange が入っていれば拡張スキーマも同じように検索できます。