Powershell – LDAP Query behind Get-ADUser commandlet

active-directorypowershell

How can I view LDAP Query executed by Get-ADUser behind the scenes, ie. this command

Get-ADUser -Filter * -Properties * | Where { $_.Enabled -eq $True } | Where { $_.PasswordNeverExpires -eq $False } | Where { $_.PasswordExpired -eq $False }

I would like to know exact LDAP query sent to Active Directory servers.

Edit: I am trying to convert some Powershell scripts to Python, therefore I need raw LDAP query I can feed to python-ldap.

Edit2: Active Directory Administrative Center has nice feature for learning LDAP queries. In Global search you can build query by using keywords and ticking checkboxes, and than click on Convert to LDAP. Enjoy nice and complex LDAP query.

ADAC GUI

Best Answer

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.