AD内の各ユーザのパスワードの有効期限が切れる失効日を求めるプログラムを掲載します。VBScriptですが、スクリプトセンターにサンプルスクリプトが掲載されているので、下記リンク先も、参考になると思います。

パスワード失効日の判別
http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/pwds/uspwvb08.mspx

動作環境は次の通りです。

  • 動作環境:Windows 2003 (AD環境)
  • 開発環境:Visual Studio 2008 Professional
  • .NET 3.0

1. サンプルソース

Visual Studio を起動して、コンソールアプリケーションプロジェクトを作成します。プロジェクトの参照の追加で、System.DirectoryServices.dllを参照に追加します。次のプログラムをデフォルトで作成される。Program.csに記述すれば、ユーザのパスワードの有効期限を調べることができます。計算方法は、最後にパスワードを変更した日付に、パスワードの有効期限を求めることでパスワードの失効日を求めています。

using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;

namespace PasswordExpirationInfo
{
    class Program
    {
        /// <summary>
        /// ユーザ検索ルート文字列
        /// 指定しないと、ADのルート
        /// </summary>
        static string _searchRootPath = null;

        /// <summary>
        /// パスワードが無期限に設定されているかのフラグ
        /// </summary>
        static readonly int ADS_UF_DONT_EXPIRE_PASSWD = 0x10000;

        /// <summary>
        /// パスワードの有効期限
        /// </summary>
        private static TimeSpan _maxPwdAge = new TimeSpan();

        static void Main(string[] args)
        {
            PasswordExpireTest("user03");
            Console.ReadLine();
        }
        static void PasswordExpireTest(string samAccount)
        {
            using (DirectoryEntry domain = CreateDomainRootEntry())
            {
                DirectorySearcher ds = new DirectorySearcher(domain, "(objectClass=domainDNS)"
                    , new string[] { "maxPwdAge" }
                    , SearchScope.Base);

                SearchResult result = ds.FindOne();
                if (result == null)
                {
                    throw new ApplicationException("ドメイン情報を検索できませんでした");
                }
                long tick = (long)result.Properties["maxPwdAge"][0];
                if (tick == long.MinValue)
                {
                    _maxPwdAge = new TimeSpan(0L); // 無期限
                }
                else
                {
                    _maxPwdAge = new TimeSpan(Math.Abs(tick));
                }
                Console.WriteLine(GetExpiration(samAccount).ToLongDateString());
            }
        }
        public static DateTime GetExpiration(string samAccount)
        {
            using (DirectoryEntry searchRoot = GetSearchRoot())
            {
                SearchResult searchResult = SearchUser(searchRoot, samAccount);
                if (searchResult != null)
                {
                    // ユーザアカウントコントロール取得
                    int userAccountControl = (int)searchResult.Properties["userAccountControl"][0];
                    // 最後にパスワードを変更した日時を取得
                    long ticks = (long)searchResult.Properties["pwdLastSet"][0];

                    return GetExpiration(userAccountControl, ticks);
                }
                else
                {
                    throw new ApplicationException("ユーザがみつかりません");
                }
            }
        }
        /// <summary>
        /// searchRootを検索のルートとして、アカウントがsAMAccountNameのユーザを検索する。
        /// </summary>
        /// <param name="searchRoot">検索するルートのDirectryEntry</param>
        /// <param name="sAMAccountName">検索対象のユーザのSAMAccount</param>
        /// <returns>検索結果.見つからない場合はnull.</returns>
        private static SearchResult SearchUser(DirectoryEntry searchRoot, string sAMAccountName)
        {
            SearchResult result = null;
            using (DirectorySearcher ds = new DirectorySearcher(searchRoot))
            {
                string filter = "(&(objectClass=user)(sAMAccountName={0}))";
                ds.Filter = string.Format(filter, sAMAccountName);
                ds.SizeLimit = 1;
                ds.PropertiesToLoad.Add("userAccountControl");
                ds.PropertiesToLoad.Add("pwdLastSet");
                ds.SearchScope = SearchScope.Subtree;
                   result = ds.FindOne();
            }
            return result;
        }
        private static DirectoryEntry GetSearchRoot()
        {
            if (string.IsNullOrEmpty(_searchRootPath))
            {
                return CreateDomainRootEntry();
            }
            return CreateDirectoryEntry(_searchRootPath);
        }
        /// <summary>
        /// userAccountControlを調べて無期限に設定されているか調べる
        ///  ticksはパスワードを最後に変更したプロパティpwdLastSetの値
        /// 
        /// _maxPwdAgeを調べて、起源が設定されていないかも調べ、最後の
        /// パスワードを変更した日時+_maxPwdAgeから失効日を求める。
        /// </summary>
        /// <returns></returns>
        private static DateTime GetExpiration(int userAccountControl, long ticks)
        {
            if (Convert.ToBoolean(userAccountControl & ADS_UF_DONT_EXPIRE_PASSWD))
            {
                // パスワードは無期限
                return DateTime.MaxValue;
            }

            if (ticks == 0)
            {
                // ユーザは次回ログイン時にパスアワードを変更する必要がある
                return DateTime.MinValue;
            }
            //if (ticks == -1)
            //{
            //    throw new ApplicationException("パスワードが設定されていません");
            //}

            if (_maxPwdAge.Ticks == 0L)
            {
                // パスワードの期限は無期限
                return DateTime.MaxValue;
            }
            DateTime pwdLastSet = DateTime.FromFileTime(ticks);

            return pwdLastSet.Add(_maxPwdAge);
        }

        public static DirectoryEntry CreateDirectoryEntry(string adsPath)
        {
            string username = null;
            string password = null;

            DirectoryEntry entry = new DirectoryEntry(adsPath, username, password, AuthenticationTypes.Secure);

            // 接続ミスがすぐ分かるように、プロパティに一度アクセスする
            object o = entry.NativeObject;
            return entry;
        }

        public static DirectoryEntry CreateDomainRootEntry()
        {
            using (DirectoryEntry rootDSE = CreateDirectoryEntry("LDAP://RootDSE"))
            {
                // RootDSEからドメインルートエントリのパスを取得する
                string defaultNamingContext = rootDSE.Properties["defaultNamingContext"].Value as string;
                return CreateDirectoryEntry("LDAP://" + defaultNamingContext);
            }
        }

    }
}

PasswordExpireTestの引数に有効期限を調べたいユーザアカウントを指定することで、失効日を求めることができます。

2. まとめ

説明は以上です。誤り、指摘点がありましたらご連絡ください。