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. まとめ
説明は以上です。誤り、指摘点がありましたらご連絡ください。
さんのコメント: さんのコメント: