System.DirectoryServices 名前空間を使って LDAP 検索をする
はじめに
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
クラスのオブジェクトが取得できます。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 が入っていれば拡張スキーマも同じように検索できます。
Discussion