There was I, deploying PSPasswordExpiryNotifications for one of my Clients when I started getting complaints that some users are not getting their Password Expiry Notifications. Well, that's a new one. I've tested this script multiple times, and it worked just fine. So I dive into the details of my script to see what I did in there (I don't even remember anymore – it just works) to find out this little line:
$Users = Get-ADUser -filter { Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0 -and PasswordNotRequired -ne $True } -Properties $Properties -ErrorAction Stop
Looks good to me! I want to find all users that are enabled, that have passwords that expire, that have password last set date and finally that they do indeed require a password. The previous condition I did to mostly get rid of some false positives, especially for Domain Trusts that create a User object called DOMAIN$. In my test domain it looks like this:
Just a standard set of objects you would expect in your Active Directory domain. To my surprise in this particular domain, I would get 86 objects filtered out because of this condition. That's a lot of accounts, legitimate accounts that shouldn't have PasswordNotRequired set to True. Supposedly the issue happens if there are identity management systems that fail to set that flag to $False when finishing up user setup. While not critical because most likely those users have proper passwords in place I prefer clean domain so here's my fix.
Well, now that I know I have 86 objects that have PasswordNotRequired flag I need to fix it. First let's find out who that is:
$Users = get-aduser -Filter { PasswordNotRequired -eq $True } -Properties DisplayName $Users | Format-Table SamAccountName, Name, Enabled, GivenName, DisplayName
Now that we have that list, I want to filter out accounts that start or end with $, and few accounts that I want to leave at their defaults.
$FilterOut = @( 'IUSR_' 'IWAM_' 'Guest' ) $UsersFilteredOut= foreach ($_ in $Users) { if ($_.SamAccountName.StartsWith('$')) { continue } if ($_.SamAccountName.EndsWith('$')){ continue } foreach ($Filter in $FilterOut) { if ($_.SamAccountName.StartsWith($Filter)){ $Found = $True break } } if ($Found) { $Found = $false continue } $_ } $UsersFilteredOut | Format-Table SamAccountName, Name, Enabled, DisplayName
Finally, if we're happy with the list, we need to set PasswordNotRequired to $false.
foreach ($_ in $UsersFilteredOut) { Set-ADuser $_ -PasswordNotRequired $false -WhatIf }
And you are done! Keep in mind that if Password would be indeed empty above command wouldn't work and give you an error. You would need to investigate such an account whether indeed such account should be left without a password. There are reasons that password for some account is not set, but for standard users, this shouldn't happen really. Running above code is fairly safe. As long as you won't remove WhatIf no changes will be done to your Active Directory. I would recommend trying out the first command, then working out what you need and what you don't need with a second script block, finally running fix on the users that we wanted to fix.