Monday, January 03, 2005

When does my Password Expire?

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;
    }
}
Comments are closed.