In Active Directory (AD), the PasswordLastSet and pwdLastSet attributes refer to the same property of an AD object – the time and date when the password for that object was last changed. This attribute is used to enforce password policies and track when a password was last changed.
This quick post helps you understand these two values and how to call them using PowerShell.
Table of Contents
Prerequisites
Get your PowerShell ready and ensure you have the proper permission, such as Domain Admin.
Also, it would be best if you had Active Directory PowerShell Module.
What is PwdLastSet vs PasswordLastSet
The PwdLastSet attribute is an Active Directory attribute that stores information about the last time a password was changed for an object. This value type is a LargeInteger representing dates as the number of 100-nanosecond intervals since January 1, 1601, 12:00 AM. The time is always stored in Greenwich Mean Time (GMT). The PasswordLastSet property converts this LargeInteger into a date-time value in the current time zone.
When working with AD Users object, reading the PasswordLastSet is much easier than reading the PwdLastSet. Check the example below for more details.
Get-ADuser ValidUser -Properties PasswordLastSet,PwdLastSet | Select-Object Name,PasswordLastSet,Pwdlastset
Name PasswordLastSet Pwdlastset
---- --------------- ----------
ValidUser 20-Jan-23 11:26:54 AM 132739180149651303
The PasswordLastSet is derived from the AD attribute PwdLastSet.
If a password is not set, the PwdLastSet value is 0, and PasswordLastSet will be absent. In cases were the “User must change password at next logon” option is selected in ADUC, the PwdLastSet value will be set to 0, resulting in the absence of PasswordLastSet.
Get-ADuser Test -Properties passwordlastset,pwdlastset | Select-Object Name,PasswordLastSet,Pwdlastset
Name PasswordLastSet Pwdlastset
---- --------------- ----------
Test 0
If a user has a recent value for LastLogon but is missing PasswordLastSet, it indicates that the user must change their password at their next logon, with PwdLastSet being set to 0.
the PasswordLastSet and PwdLastSet attributes are replicated across all domain controllers in an Active Directory (AD) environment. The replication of this attribute ensures that all domain controllers have the same value for a user’s password last set time. This allows for consistent enforcement of password policies and helps to ensure the security of the AD environment.
Getscreen.me is a cloud-based software providing a remote access via a browser. Connection is performed via a link without installing additional programs. The service is suitable for administration, technical support, as well as for remote connection to an office computer from home. Windows, macOS, Linux and Android versions are available.
get screen
UserAccountControl And Password Never Expires Using PowerShell
Another possible case for PwdLastSet to be 0 can be:
- The account was created, but the password was never set.
- The administrator created an AD user account, and the password was set while creating the user, but the User Must Change Password at Next Logon was checked.
- The administrator has checked the User Must Change Password at Next Logon option for the user in the AD user property.
Multiple ways to check if the Password Never Expires option is selected. For instance, you can check the user property using ADUC, or using PowerShell AD User property PasswordNeverExpires.
But let’s go a bit deeper and discover the roots of this value by digging into the UserAccountControl value.
The UserAccountControl represents some basic properties for the AD account status like, account enabled, disabled, Password Never Expires…and more. Reading the value from ADUC for an AD User shows a decimal number such as 512 which means that the account is normal and active.
The Password Never Expires value is 65536. Adding these two values together, 65536+512=66048
But where did these values come from? The UserAccountControl is 4 Bytes which contains 32 bits (Binary). These are bits flags (1 or 0). The Password Never Expires bit is the 15th bit. So some conversion may be required to convert the value from decimal to binary.
An easy and comprehensive explination about these bits can be found in SelfADSI.org , Attributes for AD Users : userAccountControl
Luckily PowerShell has an easy way to find these accounts without having to go through the hassle of reading and converting the value from decimal to binary. Here is an example code
PS> Get-ADUser Test -Properties PwdLastSet,PasswordNeverExpires | Select-Object Name,PwdLastSet,PasswordNeverExpires
Name PwdLastSet PasswordNeverExpires
---- ---------- --------------------
Test 0 True
If you want the complex way and want to convert the value to binary and read it. No worry, here is the code.
$UAC=Get-ADUser Test -Properties UserAccountControl
$binary = [Convert]::ToString($UAC.UserAccountControl, 2).PadLeft(32, '0')
if ($binary.Chars(15) -eq [System.Convert]::ToString('1',2)){Write-Host "$($UAC.Name) Password is set to never expires"}
Test Password is set to never expires
You might need this conversion method to find a certain bit property of a user.
How To Change PwdLastSet Attribute
To change the value of the PwdLastSet attribute, you can use various tools such as the Active Directory Users and Computers console, the Set-ADUser cmdlet in PowerShell, or an LDAP editor such as LDP.
The possible values that PwdLastSet can hold are:
0
: Indicates that the password has never been set.-1
: Indicates that the password does not expire. This doesn’t mean that the password will never expire. But, once the user login after the PwdLastSet is set to -1, the date and time value of the PwdLastSet is set to the corresponding current date/time.any other value
: Represents the date and time when the password was last changed as a large integer representing the number of 100-nanosecond intervals since January 1, 1601.
You can only set the value of the PwdLastSet to 0 or -1. No other value is accepted.
How to Reset PwdLastSet using PowerShell
You can reset this value using PowerShell using the following steps:
- Start PowerShell and import the Active Directory PowerShell module.
- Type the following code.
Set-ADUser -Identity test -Replace @{'Pwdlastset'='0'}
Or you can use the -1 instead of 0
Set-ADUser -Identity test -Replace @{'Pwdlastset'='-1'}
How to read the PwdLastSet value
The PwdLastSet value is a long number, something like this 132739180149651303. To read this value first, we need to convert it to a date and time we can understand.
Using PowerShell, we can use the FromFileFormat method from the DateTime class.
To call a class in PowerShell, use the class name between brackets [ ], so its [DateTime] and to call the method in the class, use a double-colon :: and type the FromFileFormat method.
The method requires input to take action, so pass the PwdLastSet as the input.
The full PowerShell cmdlet looks like
[Datetime]::FromFileFormat($_.PwdLastSet)
Take a look at What is PowerShell and Why to use it post to learn more about PowerShell and PowerShell classes.
Read PwdLastSet with Get-ADUser
To read the PwdLastSet attribute of an Active Directory User, we can use the Get-ADUser cmdlet in PowerShell. For example, to retrieve the PwdLastSet value for a user with the SamAccountName “Test“, we can run the following line.
PS> $DateTimeValue=(Get-ADUser Test -Properties PwdLastSet).PwdLastset
[DateTime]::FromFileTime($DateTimeValue)
03-Feb-23 3:35:00 PM
To display user information along with PwdLastSet, use the following line
The DateTime conversion happens in an expression within the Select-Object
PS> Get-ADUser Test -Properties PwdLastSet | Select-Object Name,UserPrincipalName,@{N="PasswordDate";e={[DateTime]::FromFileTime($_.Pwdlastset)}}
Name UserPrincipalName PasswordDate
---- ----------------- ------------
Test Test@Domain.com 03-Feb-23 3:35:00 PM
Review Accounts where the PwdLastSet is zero (User Must Change Password Next Login)
Using the PowerShell line below, you can get a list of all Active Directory users that have the PwdLastSet equal to zero, which means that the user must change the password next login.
PS> Get-ADUser -Properties PwdLastSet -Filter 'PwdLastSet -eq 0'
DistinguishedName : CN=User1,DC=Domain,DC=com
Enabled : True
GivenName : User1
Name : User1
ObjectClass : user
pwdlastset : 0
SamAccountName : User1
UserPrincipalName : User1@domain.com
Get All AD Users with Password Ages Older Than X Number of Days
You might need to run a query in your Active Directory to get a list of users with passwords older than a number of days. This can be a good start to sending users a notification about their password expiry so they change it before it expires.
$PasswordOlderThan=(Get-date).AddMonths(-1)
Get-ADUser -Properties PasswordLastSet -Filter 'PasswordLastSet -lt $PasswordOlderThan' | Select-Object Name,PasswordLastSet
The output is a list of users with passwords older than one month.
Name PasswordLastSet
---- ---------------
test-it 25-Sep-20 1:41:45 PM
test2 07-Jan-16 12:50:51 PM
Test3 03-May-21 1:49:54 PM
Using msDS-UserPasswordExpiryTimeComputed
Another way to handle password expiry in Active Directory is using the msDS-UserPasswordExpiryTimeComputed. This attribute is a computed time for when the AD object password will expire. This attribute is great as it saves us some small calculations to know when the user’s password will expire. This can also be very helpful when using multiple password policies.
So if User1 password is set on the 1st of Jan and the password expiry policy is after 15 days. the msDS-UserPasswordExpiryTimeComputed will be the 15th of Jan.
The msDS-UserPasswordExpiryTimeComputed value calculation is the same as PwdLastSet, a none readable date format. We can use the same method for the PwdLastSet to convert it to a readable format.
Please note that the msDS-UserPasswordExpiryTimeComputed is blank if Password Never Expire is checked.
One other thing is that msDS-UserPasswordExpiryTimeComputed takes in to account Fine Grained Password Policies. So if a AD user is assigned a Fine Grained Password Policies and the policy dont require a password age, then the msDS-UserPasswordExpiryTimeComputed will be never, even though the Password Never expires is not checked
A great comment and addition to this post from Adam D
This can be problematic in some environments as not all applications honor fine-grained password policies, such as Citrix Storefront
PS > Get-ADUser -Properties PasswordLastSet,msDS-UserPasswordExpiryTimeComputed -Filter * | Select-Object Name,PasswordLastSet,@{N="msDS-UserPasswordExpiryTimeComputed";E={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}}
Name PasswordLastSet msDS-UserPasswordExpiryTimeComputed
---- --------------- -----------------------------------
test2 04-Feb-23 10:54:50 AM
test 03-Feb-23 4:15:02 PM 04-May-23 4:15:02 PM
Thats for today. Looking to read more? We got some for you, and also join me to be inform once a new post is released.
The PwdLastSet is not Epoch format (number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970). It’s Windows file time format; a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC).
Thanks for the correction.
Updated
Nice article, Faris, just a couple of points.
There are a couple of circumstances that the pwdLastSet attribute can be equal to 0, pwdLastSet being 0 by itself doesn’t mean that the password is set to change at next logon.
https://learn.microsoft.com/en-us/services-hub/health/remediation-steps-ad/review-accounts-whose-attribute-pwdlastset-has-a-zero-value
To ascertain if change at next login is set you also need to check for the UF_DONT_EXPIRE_PASSWD flag in userAccountControl as well as pwdLastSet being 0.
https://learn.microsoft.com/en-us/windows/win32/adschema/a-pwdlastset
One other thing is that msDS-UserPasswordExpiryTimeComputed takes in to account fine grained password policies, if used, and the default domain policy if they’re not. So if no max age is stipulated in the policy, then that is also a never expiring password and msDS-UserPasswordExpiryTimeComputed will calculate as never, without needing to actually set the password never expires flag. This can be problematic in some environments as not all applications honour fine grained password policies, such as Citrix Storefront.
https://docs.citrix.com/en-us/storefront/1912-ltsr/configure-authentication-and-delegation/password-expiry.html
Cheers,
Thanks for the comment.
I wrote a section about the UserAccountControl and how to do the calculation. It was fun.
And also pointed out the msDS-UserPasswordExpiryTimeComputed and the fine-grained password policies.
Hi Faris, thanks for the article! This is very helpful. If this is not too much trouble for asking, would you happen to have a script to Change PwdLastSet Attribute in bulk using a csv file?
Hi
You can use the following cmdlet
assuming the the csv file header is Username such as
Username
——–
User1
User2
User3
$AllCSV=Import-csv PATH_TO_CSV.csv
foreach ($SingleAccount in $allCSV){
Set-ADUser -Identity $singleAccount.Username -Replace @{‘Pwdlastset’=’-1′}
}
It can be shortner, but keep it simple and clear
Hope that help