🔍

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