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 を使用して複数の値を 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