8
votes

In Active Directory, if a user's account is disabled and then enabled, by default, the user must change their password on first login. I am struggling to be able to detect this programmaticly using C#? Is there a property that is set or something along those lines if a user must reset their property?

Say I have a DirecotryEntry object pointing to a user:

DirectoryEntry user = ...

Is there a property that I can use:

user.Properties[someProperty];
4

4 Answers

8
votes

The condition is stored in two attributes:

  • pwdLastSet : If the value is set to 0 ...
  • userAccountControl : and the UF_DONT_EXPIRE_PASSWD flag is not set.

From here.

6
votes

Here is what I wrote to do this. Not exactly answering your question but useful to others who read it later.

The important bits are from PrincipalContext on. All the stuff above that is just how I tried to always get the AdName back with the exact correct capitalization.

Note this is just the code do do the first answer, test LastPasswordSet using a user principal instead of a DE.

Eric-

     private bool TestAdShouldChangePassword( string adUser )
     {
                    try
                    {
                        string adName = "";
                        MembershipUser mu = Membership.GetUser( adUser );

                        if ( mu != null )
                        {
                            IStudentPortalLoginBLL splBll = ObjectFactory.GetInstance< IStudentPortalLoginBLL >();
                            adName = splBll.GetCleanAdName( adUser );// I wrote this is just pulls outhe name and fixes the caplitalization - EWB

                            PrincipalContext pctx = new PrincipalContext( System.DirectoryServices.AccountManagement.ContextType.Domain );
                            UserPrincipal p = UserPrincipal.FindByIdentity( pctx, adName );

                            if ( p == null )
                                return false;

                            if ( p.LastPasswordSet.HasValue == false && p.PasswordNeverExpires == false )
                            {
                                return true;
                            }
                        }
                    }
                    catch ( MultipleMatchesException mmex )
                    {
                        log.Error ( "TestAdShouldChangePassword( ad user = '" + adUser + "' ) - Exception finding user, can't determine if ad says to change password, returing false : Ex = " + mmex.ToString() );
                    }

                    return false;
      }
3
votes

Was able to get it using the following code:


        public bool PasswordRequiresChanged(string userName)
        {
            DirectoryEntry user = GetUser(userName); //A directory entry pointing to the user
            Int64 pls;
            int uac;

            if (user != null && user.Properties["pwdLastSet"] != null && user.Properties["pwdLastSet"].Value != null)
            {
                pls = ConvertADSLargeIntegerToInt64(user.Properties["pwdLastSet"].Value);           
            }
            else
            {
                throw new Exception("Could not determine if password needs reset");
            }

            if (user != null && user.Properties["UserAccountControl"] != null && user.Properties["UserAccountControl"].Value != null)
            {
                uac = (int)user.Properties["UserAccountControl"].Value;
            }
            else
            {
                throw new Exception("Could not determine if password needs reset");
            }

            return (pls == 0) && ((uac & 0x00010000) == 0) ? true : false;
        }


 private static Int64 ConvertADSLargeIntegerToInt64(object adsLargeInteger)
        {
            var highPart = (Int32)adsLargeInteger.GetType().InvokeMember("HighPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
            var lowPart = (Int32)adsLargeInteger.GetType().InvokeMember("LowPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
            return highPart * ((Int64)UInt32.MaxValue + 1) + lowPart;
        }

1
votes
var username = "radmin";
var adContext = new PrincipalContext(ContextType.Domain, adLocation, adContainer, adAdminUsername, adAdminPassword);
var user = UserPrincipal.FindByIdentity(adContext, username);
Console.WriteLine(user.LastPasswordSet);

If LastPasswordSet has a null value, the "user must change password at next logon".