Why does the LastPasswordSet property always change?

301 views Asked by At

I try to get a LastPasswordSet datetime for a Windows local account "toto" with C#

This property value always change (millisecond or second).

Do you have any idea for fix it ? Do you have a same comportement ?

for (int i = 0; i < 100; i++)
{

    PrincipalContext context = new PrincipalContext(ContextType.Machine);
    UserPrincipal user = new UserPrincipal(context) { SamAccountName = "toto" };
    user = (UserPrincipal)new PrincipalSearcher(user).FindOne();
    Debug.WriteLine("User : " + user.LastPasswordSet.Value.ToString("dd/MM/yyyy HH:mm:ss.fff"));
}
User : 01/06/2020 09:09:34.475
User : 01/06/2020 09:09:34.479
User : 01/06/2020 09:09:34.484
User : 01/06/2020 09:09:34.489
User : 01/06/2020 09:09:34.494
User : 01/06/2020 09:09:34.499
User : 01/06/2020 09:09:34.504
User : 01/06/2020 09:09:34.509
User : 01/06/2020 09:09:34.513
User : 01/06/2020 09:09:34.519
User : 01/06/2020 09:09:34.524
User : 01/06/2020 09:09:34.528
User : 01/06/2020 09:09:34.533
User : 01/06/2020 09:09:34.538
User : 01/06/2020 09:09:34.542
User : 01/06/2020 09:09:34.547
User : 01/06/2020 09:09:34.552
User : 01/06/2020 09:09:34.557

Thanks for your answer.

How is it calculated PasswordAge ???

I wanted to use LastPasswordSet to find out if a password has changed but this data is not fixed and the comparison is not secure. By taking that milliseconds sometimes the second goes to the next.

Really strange that LastPasswordSet is not the data used to calculate PasswordAge and not vice versa


Hello i try this code but the property LastPasswordSet not exist

var user = new DirectoryEntry("WinNT://./toto");
var lastSet = user.LastPasswordSet.Value;
var lastSetNoMilliseconds = new DateTime(lastSet.Year, lastSet.Month, lastSet.Day, lastSet.Hour, lastSet.Minute, lastSet.Second, lastSet.Kind);
1

There are 1 answers

0
Gabriel Luci On

Windows doesn't actually expose any property that tells you when the password was last set. It does expose a property called PasswordAge, which you can see if you use DirectoryEntry (which is what UserPrincipal uses in the background anyway):

var user = new DirectoryEntry("WinNT://./toto");
Debug.WriteLine($"PasswordAge: {user.Properties["PasswordAge"][0]}");

That PasswordAge value represents the number of seconds that have passed since the password was last changed. So if you want to convert that into the actual time that the password was changed, you have to subtract that value from the current time, which is what UserPrincipal will do for you when you access the LastPasswordSet property, as you can see in their code:

value = DateTime.UtcNow - new TimeSpan(0, 0, secondsLapsed);

But since the PasswordAge only has seconds, that means that the millisecond value that you get comes from the current time.

So nothing is wrong. Just don't look at the millisecond value.

Update: If you are storing this value to compare later, you can copy the date without the milliseconds:

var lastSet = user.LastPasswordSet.Value;
var lastSetNoMilliseconds = new DateTime(lastSet.Year, lastSet.Month, lastSet.Day, lastSet.Hour, lastSet.Minute, lastSet.Second, lastSet.Kind);