Monday, January 3, 2005
Here is a quick and dirty way to figure out when your account (or anyone else's) will expire on the domain.
Prerequisites:
1. You must be running this from a computer joined to the domain.
2. You must be running this with valid domain credentials.
How does it work:
There is no attribute that directly holds when your password expires. It is a calculation done based on two factors - 1. When you last set your password (pwdLastSet), and 2. What your domain policy for the maximum password age (MaxPwdAge) is.
Here is a simple command line app to demonstrate how this is done:
using System;
using System.DirectoryServices;
using System.Reflection;
class Invoker
{
[STAThread]
static void Main(string[] args)
{
try
{
if (args.Length != 1)
{
Console.WriteLine("Usage: {0} username", Environment.GetCommandLineArgs()[0]);
return;
}
PasswordExpires pe = new PasswordExpires();
Console.WriteLine("Password Policy: {0} days", 0 - pe.PasswordAge.Days);
TimeSpan t = pe.WhenExpires(args[0]);
if(t == TimeSpan.MaxValue)
Console.WriteLine("{0}: Password Never Expires", args[0]);
else if(t == TimeSpan.MinValue)
Console.WriteLine("{0}: Password Expired", args[0]);
else
Console.WriteLine("Password for {0} expires in {1} days at {2}", args[0], t.Days, DateTime.Now.Add(t));
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString()); //debugging info
}
}
}
class PasswordExpires
{
DirectoryEntry _domain;
TimeSpan _passwordAge = TimeSpan.MinValue;
const int UF_DONT_EXPIRE_PASSWD = 0x10000;
public PasswordExpires()
{
//bind with current credentials
using (DirectoryEntry root = new DirectoryEntry("LDAP://rootDSE", null, null, AuthenticationTypes.Secure))
{
string adsPath = String.Format("LDAP://{0}", root.Properties["defaultNamingContext"][0]);
_domain = new DirectoryEntry(adsPath, null, null, AuthenticationTypes.Secure);
}
}
public TimeSpan PasswordAge
{
get
{
if(_passwordAge == TimeSpan.MinValue)
{
long ldate = LongFromLargeInteger(_domain.Properties["maxPwdAge"][0]);
_passwordAge = TimeSpan.FromTicks(ldate);
}
return _passwordAge;
}
}
public TimeSpan WhenExpires(string username)
{
DirectorySearcher ds = new DirectorySearcher(_domain);
ds.Filter = String.Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))", username);
SearchResult sr = FindOne(ds);
int flags = (int)sr.Properties["userAccountControl"][0];
if(Convert.ToBoolean(flags & UF_DONT_EXPIRE_PASSWD))
{
return TimeSpan.MaxValue; //password never expires
}
//get when they last set their password
DateTime pwdLastSet = DateTime.FromFileTime((long)sr.Properties["pwdLastSet"][0]);
if(pwdLastSet.Subtract(PasswordAge).CompareTo(DateTime.Now) > 0)
{
return pwdLastSet.Subtract(PasswordAge).Subtract(DateTime.Now);
}
else
return TimeSpan.MinValue; //already expired
}
private long LongFromLargeInteger(object largeInteger)
{
System.Type type = largeInteger.GetType();
int highPart = (int)type.InvokeMember("HighPart",BindingFlags.GetProperty, null, largeInteger, null);
int lowPart = (int)type.InvokeMember("LowPart",BindingFlags.GetProperty, null, largeInteger, null);
return (long)highPart << 32 | (uint)lowPart;
}
private SearchResult FindOne(DirectorySearcher searcher)
{
SearchResult sr = null;
using (SearchResultCollection src = searcher.FindAll())
{
if(src.Count>0)
{
sr = src[0];
}
}
return sr;
}
}