Active Directory user account pwdLastSet field not updating

We have written a simple perl script which binds to a AD domain controller and allows AD users to reset their password across multiple systems through one simple interface (Unix, LDAP etc.).  The script modifies the unicodePwd attribute in active directory and we've successfully tested that indeed the user account password does change.  We have an additional script which generates an email and notifies users that their password is over X number of days old.  We're finding that the pwdLastSet field is not updating as a result of the password change.  Is there some process that comes along and updates this attribute on a schedule?  I've found that when using the change password functionality within XP/2K etc., the pwdLastSet field updates instantly.

Anyone have any ideas?  Thanks!
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Since you are accessing the unicodePwd attribute directly you will also need to modify the pwdLastSet directly with your script.  The mechanism to change passwords in Windows modifies more then just the unicodePwd attribute.

jasgbairAuthor Commented:
I was under the impression from everything that I've read that the pwdLastSet could NOT be directly modified and could only be set to 0 or 1.  
I'm not near something I can open up the Schema on - can I look at this tonight and provide some more input?

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

jasgbairAuthor Commented:
Absolutely---any input is appreciated!
Alright, I'm home now.

Can you send me a snippit of the code you are using that accesses these attributes?  I want to make sure I'm looking for them in the right place.

Ok, I think I see what you are trying to do.

It looks like the value of pwdLastSet is a decimal value for time based on number of seconds (?) from the last time it was set or a fixed period of time from a point relative in time.  Forcing pwdLast Set to zero (0) will act as if you checked the box on the user's account for "User must change password at next logon".  I'm not sure you can force it to anything else, but I will attempt to find out for you.

If this isn't somehow changed, then the password would expire per the Password policy on the domain as if it was never changed.

Interesting problem.  Let's see what I can dig up.


This is convoluted so bear with me...

The value of pwdLastSet is a long integer (decimal).
Copy this value to the clipboard.
Open CALC and set it to Scientific view with DEC selected.
Paste the value into CALC using CTRL+V.
Change the CALC to HEX.
Copy the result (Edit>Copy) to the Clipboard again.
Open NOTEPAD and paste the value in there.
Count 8 positions from the left and use the Space Bar to break the value into 2 parts.
Each part must have 8 characters.  If the left part has 7, then add a zero (0) at the beginning of the part.
Now, copy this line and paste it on the next line.
Reverse the parts (left 8 characters on the right side and right 8 characters on the left side) making sure the space divides them still.
Copy this line.

From a CMD window type:  NLTEST /time:{value}

...where {value} is the reworked line from Notepad.

You should end up with a valid date and time.  This should give you the method to script a value for the current date and add it to pwdLastSet by reverse-engineering these steps.

Here is an example output from my account here:

pwdLastSet value:  126948227778416250
In HEX from CALC: 1C302BD95990E7A
Split: 01C302BD 95990E7A
Reversed: 95990E7A 01C302BD

NLTEST /time:95990E7A 01C302BD
95990e7a 01c302bd = 4/14/2003 16:39:37
The command completed successfully

Hope this helps the logic somewhat....

Let me know.
This may be a bit more involved than simply plugging in values, but you never know.

Pick a test user.

Run the following command from a CMD window:  dsquery user -name {username} -s {servername}
....where {username} can be a partial with wildcard (ie. Dan*) and {servername} is the name of your local DC.
The result should be the DN for the user - copy it.
Now run this:  repadmin /showobjmeta {servername} "{DN from last output of DSQUERY}"
....where {servername} is your local DC and {DN from last output of DSQUERY} is the output from dsquery.
Pipe the output to a text file.

Change the password normally on this account and repeat the process above.

You should notice that a number of things actually change:

4 dBCSPwd
4 unicodePwd
4 ntPwdHistory
4 pwdLastSet
4 supplementalCredentials
4 lmPwdHistory

I think the source of this operation is in user.c and calls (perhaps) SamDsSetPassword to do the dirty work.

You may or may not get this working as expected, and maybe just the unicodePwd and pwdLastSet are all that's really important - but I just wanted you to see for yourself that a password reset using normal methods does more than meets the eye.

If it wouldn't be too much to ask, can you get a Repadmin output as above on a user account before and then directly after you run your script against it?  I'd like to compare the two so I can see what happens with your script.  I may also have a request to capture the code to and from AD during this process - more on the steps to do this shortly.  I give you my word that this is to be kept between you, me and one Escalation Engineer I know who is helping me figure out how we can best get your script functional without breaking anything.

Let me know.

Re: the capture request - I just need the section of code (your Perl script) that handles the AD password stuff.  

Now, with repect to stuffing the pwdLastSet attribute; if you could manage to convert the current date/time to long integer and feed that to the attribute that should work.

Just found an easier way to decode the pwdLastSet.

w32tm /ntte {pwdLastSet}

Go figure...

pwdLastSet - values that you can use are 0 and -1.

Too bad.

This looks like a bug report - you shouldn't be able to set the password using any method without the pwdLastSet being modified.

Can't get anything to work other than 0.

jasgbairAuthor Commented:
Thank you so much Netman66 for the help.  Interestingly enough we've found that the script works fine with other accounts but not with the one we were testing with.  Go figure.  Have to dig in further.  
Any chance of getting the section of code you are using for the AD password change and a report before and after one of those non-working accounts gets the password changed?

MS wants to see if there is a bug and it'll get fixed.

jasgbairAuthor Commented:
Sure thing!  I'll get the code for you on Monday.  
Great!  Can you send it to my alias at gmail?

PAQed with points refunded (500)

Community Support Moderator

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Windows Server 2003

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.