Password expiring in 30 days

Hi Team,

I am trying to get the user list of users, whose password expiring in 30 days but not getting this to work. Can someone please help?

$PasswordExpireLimitDate = (Get-Date).AddDays(30).ToLongDateString()
$SearchBase = ‘OUPATH’

$ADUserList = Get-ADUser -SearchBase $SearchBase -Filter “Enabled -eq ‘$true’ -and PasswordNeverExpires -eq ‘$False’” -Properties ‘DisplayName’, ‘msDS-UserPasswordExpiryTimeComputed’, ‘emailaddress’ | ft |

$PasswordExpireDate = [datetime]::FromFileTime($($ADUser.‘msDS-UserPasswordExpiryTimeComputed’)).Date

foreach ($User in $ADUserList) {

if ($PasswordExpireDate -lt $PasswordExpireLimitDate) {
    $ExpireDaySpan = New-TimeSpan -Start (Get-Date).Date -End $PasswordExpireDate


Get-ADUser | Select-Object -Property “Name”, “EmailAddress”


Welcome to the forum. :wave:t4:

First of all … most of the time you’re not the very first one with a given task. You should search for code examples online. I am sure you will find several examples from people already accomplished this task.

Second …

… that’s not helpful at all. What happens? Or what happens not? Please be as precise and as verbose as possible and keep in mind - we cannot see your screen and we cannot read your mind. :wink:

Third …

When you post code, sample data, console output or error messages please format it as code using the preformatted text button ( </> ). Simply place your cursor on an empty line, click the button and paste your code.

Thanks in advance

How to format code in <---- Click :point_up_2:t4: :wink:

… next …

When you compare dates and times you should not use the string representation of the [DateTime] types like (Get-Date).AddDays(30).ToLongDateString() … omit the .ToLongDateString() for proper comparisons.

… next … format cmdlets are meant to be used for console output only and they should be the last element in a pipeline … so something like this:

.... , ‘emailaddress’ | ft |

does not make any sense. :wink:

… next …

you set the variable $PasswordExpireDate outside the foreach loop but you use it inside. And you use the variable $ADUser to define it but you never define that. :wink:

… next …

you create the variable $ExpireDaySpan inside your foreach loop but you never use it.

and last but not least …

The query

Get-ADUser | Select-Object -Property "Name", "EmailAddress"

will enumerate ALL USERS of your AD everytime the comparison

$PasswordExpireDate -lt $PasswordExpireLimitDate

evaluates to $true inside your foreach loop. I’m pretty sure that’s not what you wanted, right? :wink:

1 Like

Get-ADUser will prompt for a filter argument. It’s not really pulling anything until you provide it.

1 Like

You’re perfectly right. :+1:t4: But the query does not make sense at this point anyway. :man_shrugging:t4: :wink:

First, thank you for bringing msDS-UserPasswordExpiryTimeComputed to my attention. I don’t recall coming across this. I am not sure how desirable it is to use it based on my Googling. It’s a calculated value when used, so that does add some overhead to the script that may or may not be a good thing. Just food for thought.

You are close to having a working script.

Some thoughts that should help you get it all working

# Original 
# $PasswordExpireLimitDate = (Get-Date).AddDays(30).ToLongDateString()

# As Olaf suggested, this works
$PasswordExpireLimitDate = (Get-Date).AddDays(30)

There are some errors in your Get-Aduser. See if you can find them.
Tips. Review the filter rules and how to handle Booleans in a filter. Review the PS quoting rules. And about pipelines

$ADUserList = Get-ADUser -Filter “Enabled -eq ‘$true’ -and PasswordNeverExpires -eq ‘$False’” -Properties ‘DisplayName’, ‘msDS-UserPasswordExpiryTimeComputed’, ‘emailaddress’ | ft |

If you want to convert each user’s msDS-UserPasswordExpiryTimeComputed value, then compare it to find how many days until expire? This is in the wrong place.

$PasswordExpireDate = [datetime]::FromFileTime($($ADUser.‘msDS-UserPasswordExpiryTimeComputed’)).Date

When you get it to the right place, you will also have to change this part


You should rethink this entire area. It is what Krzydoug is referring to his post.

            Get-ADUser | Select-Object -Property “Name”, “EmailAddress”


Since there is no filter, the script will stop till you provide one. If you use *, that pulls in everyone. If you don’t want everyone, you have to provide something more specific. Since you already have all the AD accounts you need at time of script being run, this part makes no sense.

If you are trying to see who matches your conditions and has a password expiring in 30 days, you do not need to use Get-ADuser again. You already have that info. First in $ADUserList. This is your entire collection of users that match your original get-aduser search.

Then later as individual users in your foreach loop you pull one user at a time from $ADuserlist and place them into $Users.

When you get into the IF section, you want some kind of output for the results. You have several options such as write-host, create custom object to collect the results and place in a csv file, create html report etc.
A simple example to at least verify your basic script would be something like this. Then once you confirm everything is working, you can then get fancy with how you capture the results.

if ($PasswordExpireDate -lt $PasswordExpireLimitDate) {
    $ExpireDaySpan = New-TimeSpan -Start (Get-Date).Date -End $PasswordExpireDate
            Write-host "$($ password is expiring in $ExpireDaySpan "


about Quoting Rules - PowerShell | Microsoft Learn

Get-ADUser (ActiveDirectory) | Microsoft Learn

about Pipelines - PowerShell | Microsoft Learn