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