I'm working with a new product from our cyber team that helps identify users whose passwords have been compromised in breaches. Every week, we get a list of around 50-100 users who need to have their passwords reset. Unfortunately, our setup doesn't allow us to enforce a mandatory password change at the next logon. To manage this, I'm taking the user names that need to be contacted and running some PowerShell commands to check which ones haven't reset their passwords since the alert came in.
In a SQL environment, I could easily run a query to check the password status like this:
`SELECT Name, SamAccountName, UserPrincipalName, PasswordLastSet FROM ADUser WHERE (Name in ('User1', 'User2', 'User3') AND PasswordLastSet < 'datetime')`
Now, I'm trying to replicate this in PowerShell with the following code:
`$passwordChangeDate = [DateTime] "datetime"`
`$userList = @("user1","user2","user3")`
`$userList | Get-ADUser -Filter '(PasswordLastSet -lt $passwordChangeDate)' -Properties * | Select-Object Name, SamAccountName, UserPrincipalName, PasswordLastSet`
But it doesn't seem to work. What am I missing? Any suggestions would be appreciated!
Also, I tried to import a CSV file of usernames but faced the same issue, as it returned all users instead of just the ones from the list.
5 Answers
I had a similar scenario, and this script worked well for me to output users to a CSV. It checks each user against the password change date. Here’s a quick example:
```powershell
$passwordChangeDate = Get-Date "2024-04-01"
$userList = @("user1","user2","user3")
$output = foreach ($user in $userList) {
$adUser = Get-ADUser -Identity $user -Properties PasswordLastSet
if ($adUser.PasswordLastSet -lt $passwordChangeDate) {
[PSCustomObject]@{
Name = $adUser.Name
SamAccountName = $adUser.SamAccountName
UserPrincipalName = $adUser.UserPrincipalName
PasswordLastSet = $adUser.PasswordLastSet
}
}
}
$output | Export-Csv -Path "C:PathToOutput.csv"
```
You might need to have the Remote Server Administration Tools (RSAT) installed on the machine where you’re running this command. Try this command instead:
`$date =(get-date).AddDays(-180); Get-AdUser -Properties PasswordLastSet -Filter {(PasswordLastSet -le $date) -and (Enabled -eq $True)} | Select-Object Name, UserPrincipalName, PasswordLastSet`
Why is '-Properties PasswordLastSet' necessary in this command?
This doesn't take into account your specific user list. It's querying all of AD without your filtered names.
Make sure each part of your script works correctly. Start with retrieving the users without applying a filter, and then filter the results with `Where-Object`:
```powershell
$username_list = @("Alice", "Bob", "Charlie")
$users = $username_list | ForEach-Object { Get-ADUser -Identity $_ -Property * }
```
There are a couple of things to check. First, ensure you're using double quotes in your filters for proper string interpolation, like this:
`-Filter "PasswordLastSet -lt '$passwordChangeDate'"`
Also, avoid using `SELECT *`. Just specify the properties you need with `-Properties Name, SamAccountName, UserPrincipalName, PasswordLastSet`. This helps in making your command cleaner and faster.
It’s important to select only the properties you need for efficient processing.
Just a note, the double quotes might work, but I had issues validating that with pwsh7. What did you find?
To streamline your approach, you could directly use:
`$userList | Get-AdUser -Properties Name, SamAccountName, UserPrincipalName, PasswordLastSet`
But remember, you can’t use the `-Filter` parameter at the same time. Instead, filter afterward based on the password date like this:
`... | Where-Object { $_.PasswordLastSet -lt $cutoffdate }`
This method of building PSObjects is very effective, especially when you need specific properties in your output.