The ActiveDirectory
module has clever logic that calculate "popular" properties like whether a user account is Enabled
or have PasswordNeverExpires
set and presents them like regular attributes.
Internally, they're derived from actual account attributes like userAccountControl
and pwdLastSet
.
Account Settings
userAccountControl
is a bitfield, and contains a long list of account security related settings, like "User cannot change password" and account "Disabled".
Microsoft's LDAP implementation let's you filter such an attribute with bitwise operators, identified by an Object Identifier (OID):
LDAP_MATCHING_RULE_BIT_AND: 1.2.840.113556.1.4.803
LDAP_MATCHING_RULE_BIT_OR : 1.2.840.113556.1.4.804
To find Disabled
accounts, we can use the following filter syntax:
(&(userAccountControl:1.2.840.113556.1.4.803:=2))
As always, you can negate an ldap expression with !
, in this example retrieving all Enabled
accounts:
(!(userAccountControl:1.2.840.113556.1.4.803:=2))
Likewise, a setting called DONT_EXPIRE_PASSWORD
has value 65536 (0x10000), and we can find these accounts with:
(&(userAccountControl:1.2.840.113556.1.4.803:=65536))
Password Expiration
Calculating password expiration is a bit more complicated. To aid developers and integrators, Microsoft has implemented a dynamic attribute named msDS-User-Account-Control-Computed
.
msDS-User-Account-Control-Computed
transparently returns the same value as userAccountControl
, but with the addition of the following bits, computed on the fly at lookup time:
UF_LOCKOUT 0x0010
UF_PASSWORD_EXPIRED 0x800000
UF_PARTIAL_SECRETS_ACCOUNT 0x4000000
UF_USE_AES_KEYS 0x8000000
I haven't tested this, but if memory serves me right, this should help you reliably identify accounts with expired passwords with this filter:
(&(msDS-User-Account-Control-Computed:1.2.840.113556.1.4.803:=8388608))
Unfortunately you cannot use contructed attributes in LDAP query filters, so what you'll have to do is filter on the first two statements:
(&(!userAccountControl:1.2.840.113556.1.4.803:=2)(!userAccountControl:1.2.840.113556.1.4.803:=65536))
Be sure to ask the directory server for the msDS-User-Account-Control-Computed
value, and then perform your bitwise AND mask on the results, client-side.
Where
clauses perform their work on the PowerShell object returned from theGet-ADUser
, not by querying AD again.