本サンプルでは、ドメインルートのディレクトリオブジェクトにバインドし、次のポリシーの値を取得してみます。
- パスワードの長さ
 - パスワードの変更禁止期間
 - パスワードの有効期間
 - パスワードの履歴を記録する
 - パスワードは複雑さの要件を満たす必要がある
 - 暗号化を元に戻せる状態でパスワードを保存する
 - アカウントのロックアウトの閾値
 - ロックアウトカウンタのリセット
 - ロックアウト期間
 
動作環境
- 動作環境 Windows 2003 (ドメイン環境)
 - 開発環境 Visual Studio 2008 Professional
 - .NET 3.5 (.NET 2.0 以上で動作します)
 
参考のURLです。
1 パスワードポリシーを持つディレクトリオブジェクト
パスワードのポリシーはドメインレベルのポリシーです。パスワードのポリシーを取得するには、スキーマクラスが domainDNS (objectClass=domainDNS) のディレクトリオブジェクトから取得します。このディレクトリオブジェクトのパスは RootDSE ディレクトリオブジェクトのdefaultNamingContext 属性値から得られます。つまり、ドメインのルートオブジェクトから取得できます。
2. パスワードの属性値を取得する
サンプルではルートオブジェクトにバインドし、パスワードのポリシーを取得します。プログラムでは次の属性値を取得します。
- パスワードの長さ
 - パスワードの変更禁止期間
 - パスワードの有効期間
 - パスワードの履歴を記録する
 - アカウントのロックアウトの閾値
 - ロックアウトカウンタのリセット
 - ロックアウト期間
 
/// <summary>
/// パスワードの属性値を取得する
/// </summary>
public static void RetrievePasswordAttribute()
{
    using (DirectoryEntry rootDSE = GetDirectoryEntry("RootDSE"))
    {
       // ドメインルートオブジェクトにパスワードのプロパティは格納されている
        // ので、回りくどいことをしなくても、LDAP://crm1.localのようにドメイン
        // のルートパスをを指定すれば取得できます。
        string domainRoot = rootDSE.Properties["defaultNamingContext"].Value as string;
       using (DirectoryEntry rootEntry = GetDirectoryEntry(domainRoot))
       {
            string[] policyAttributes = new string[]{
                "maxPwdAge","minPwdAge", "minPwdLength",
                "lockoutDuration", "lockOutObservationWindow",
                "lockoutThreshold", "pwdHistoryLength"
            };
            // rootEntryはobjectClassがdomainDNSのディレクトリオブジェクト
              DirectorySearcher searcher = new DirectorySearcher(rootEntry, null, policyAttributes, SearchScope.Base);
            SearchResult result = searcher.FindOne();
            if (result != null)
            {
                // パスワードの長さ
                  if (result.Properties.Contains("minPwdLength"))
                {
                    Console.WriteLine("パスワードの長さ:" + result.Properties["minPwdLength"][0] + "文字以上");
                }
                // パスワードの変更禁止期間
                  if (result.Properties.Contains("minPwdAge"))
                {
                   // 64bit 整数型はLDAPでは負数として格納されている
                      long tick = (long)result.Properties["minPwdAge"][0];
                   if (tick == long.MinValue)
                   {
                       tick = 0L;  // 無期限
                       }
                    else
                    {
                       tick = Math.Abs(tick);
                    }
                    Console.WriteLine("パスワードの変更禁止期間:" + new TimeSpan(tick).TotalDays + "日");
                }
                // パスワードの有効期間
                  if (result.Properties.Contains("maxPwdAge"))
                {
                    // 64bit 整数型はLDAPでは負数として格納されている
                       long tick = (long)result.Properties["maxPwdAge"][0];
                    if (tick == long.MinValue)
                    {
                        tick = 0L;  // 無期限
                        }
                    else
                    {
                        tick = Math.Abs(tick);
                    }
                    Console.WriteLine("パスワードの有効期間:" + new TimeSpan(tick).TotalDays + "日");
                }
                // パスワードの履歴を記録する
                   if (result.Properties.Contains("pwdHistoryLength"))
                {
                    Console.WriteLine("パスワードの履歴を記録する:" + result.Properties["pwdHistoryLength"][0] + "回");
                }
                // パスワードは複雑さの要件を満たす必要がある
                   // 暗号化を元に戻せる状態でパスワードを保存する
                   // 上記2設定は pwdProperties 属性に格納されている
                   // アカウントのロックアウトの閾値
                  if (result.Properties.Contains("lockoutThreshold"))
                {
                    Console.WriteLine("アカウントのロックアウトの閾値:" + result.Properties["lockoutThreshold"][0] + "回ログオンに失敗");
                }
                // ロックアウトカウンタのリセット
                  if (result.Properties.Contains("lockOutObservationWindow"))
                {
                     long tick = (long)result.Properties["lockOutObservationWindow"][0];
                     if (tick == long.MinValue)
                     {
                         tick = 0L;  // 無期限
                         }
                      else
                      {
                         tick = Math.Abs(tick);
                      }
                      Console.WriteLine("ロックアウトカウンタのリセット:" + new TimeSpan(tick).TotalMinutes + "分後");
                  }
                  // ロックアウト期間
                     if (result.Properties.Contains("lockoutDuration"))
                  {
                      long tick = (long)result.Properties["lockoutDuration"][0];
                      if (tick == long.MinValue)
                      {
                          tick = 0L;  // 無期限
                          }
                       else
                      {
                          tick = Math.Abs(tick);
                      }
                      Console.WriteLine("ロックアウト期間:" + new TimeSpan(tick).TotalMinutes + "分");
                  }
             }
        }
    }
}
private static DirectoryEntry GetDirectoryEntry(string path)
{
    path = "LDAP://" + path;
    return new DirectoryEntry(path, null, null, AuthenticationTypes.Secure);
}
ディレクトリの属性値について
パスワードのポリシーを未定義にしても、パスワードポリシーのプロパティ値がとれます。ポリシーが未定義とは、定義しないというのではなく、現在のポリシーを上書きしないという意味。パスワードに関するポリシーはドメインレベルでのみ定義できます。そのため、ポリシーを定義してから未定義にすると、定義時の値が有効になります。
3. パスワードのポリシーを取得する
ルートディレクトリオブジェクトの pwdProperties 属性値からパスワードのプロパティを取得し、次のパスワードのポリシーを取得するサンプルを掲載します。
- パスワードは複雑さの要件を満たす必要がある
 - 暗号化を元に戻せる状態でパスワードを保存する
 
/// <summary>
/// プロパティの説明は以下のリンク参照
/// DOMAIN_PASSWORD_INFORMATION Structure
/// http://msdn.microsoft.com/en-us/library/aa375371(VS.85).aspx
/// </summary>
[Flags]
public enum PasswordProperty
{
    DOMAIN_PASSWORD_COMPLEX = 1,
    DOMAIN_PASSWORD_NO_ANON_CHANGE = 2,
    DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 4,
    DOMAIN_LOCKOUT_ADMINS = 8,
    DOMAIN_PASSWORD_STORE_CLEARTEXT = 16,
    DOMAIN_REFUSE_PASSWORD_CHANGE = 32
}
public static void RetrievePasswordProperties()
{
    using (DirectoryEntry rootDSE = GetDirectoryEntry("RootDSE"))
    {
        // ドメインルートオブジェクトにパスワードのプロパティは格納されている
         // ので、回りくどいことをしなくても、LDAP://crm1.localのようにドメイン
         // のルートパスをを指定すれば取得できます。
         string domainRoot = rootDSE.Properties["defaultNamingContext"].Value as string;
        using (DirectoryEntry rootEntry = GetDirectoryEntry(domainRoot))
        {
            string[] passwordProperties = new string[] { "pwdProperties" };
            // rootEntryはobjectClassがdomainDNSのディレクトリオブジェクト
              DirectorySearcher searcher = new DirectorySearcher(rootEntry, null, passwordProperties, SearchScope.Base);
            SearchResult result = searcher.FindOne();
            if (result != null)
            {
                if (result.Properties.Contains("pwdProperties"))
                {
                    PasswordProperty property = (PasswordProperty) result.Properties["pwdProperties"][0];
                    Console.WriteLine(property);
                    if ((property & PasswordProperty.DOMAIN_PASSWORD_COMPLEX) == PasswordProperty.DOMAIN_PASSWORD_COMPLEX)
                    {
                        Console.WriteLine("パスワードは、複雑さの要件を満たす必要がある:有効");
                    }
                    else
                    {
                        Console.WriteLine("パスワードは、複雑さの要件を満たす必要がある:無効");
                    }
                    if ((property & PasswordProperty.DOMAIN_PASSWORD_STORE_CLEARTEXT) == PasswordProperty.DOMAIN_PASSWORD_STORE_CLEARTEXT)
                    {
                        Console.WriteLine("暗号化を元に戻せる状態でパスワードを保存する:有効");
                    }
                    else
                    {
                        Console.WriteLine("暗号化を元に戻せる状態でパスワードを保存する:無効");
                    }
                }
            }
        }
    }
}
ADSIを使用するサンプルはスクリプトですが、次のサイトが参考になります。
スクリプト一覧 : Active Directory
http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/default.mspx
                            
                            
                            
さんのコメント: さんのコメント: