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 [0] January 3, 2005
This is the personal site of Ryan Dunn, co-author of the The .NET Developers Guide to Directory Services Programming.
Ryan currently works for Microsoft and is the Technical Evangelist for Windows Azure
Buy the Book
Contact Ryan