Active Directory User Account Control Values

Recently I was tasked with conducting a quick audit of Active Directory. I was looking for user accounts who do not require a password to log into systems. I was also looking for user accounts on which passwords do not expire.

The UserAccountControl value in Active Directory stores this information. The UserAccountControl value is a 4-byte integer that represents flags on the object. This integer is calculated by performing a bitwise enumeration of these flags. When querying the full set of properties of an object, the value of UserAccountControl can be examined and interpreted to determine additional properties of the object.

The following table shows common values for the UserAccountControl property.

Description Hexadecimal Value Integer Value
ACCOUNTDISABLE 0x0002 2
PASSWD_NOTREQD 0x0020 32
NORMAL_ACCOUNT 0x0200 512
DONT_EXPIRE_PASSWORD 0x10000 65536
PASSWORD_EXPIRED 0x800000 8388608

So how exactly does this work?

A normal account has the integer value of 512 as shown above.  But a disabled normal account would have the integer value of 514.  This is the result of adding the 512 value for NORMAL_ACCOUNT and the value for ACCOUNTDISABLE, which is 2. 

User accounts that do not require a passwords have the PASSWD_NOTREQD bit added.  The first step was to search for the integer values of 544 and 546.  These values consist of the previously mentioned enabled normal account and disabled normal account, but with the PASSWD_NOTREQD value of 32 added.

  • 544 = 512 (NORMAL_ACCOUNT) + 32 (PASSWD_NOTREQD)
  • 546 = 512 (NORMAL_ACCOUNT) + 32 (PASSWD_NOTREQD) + 2 (ACCOUNTDISABLED)

A quick PowerShell yields the accounts that do not require a password.

Get-ADUser -Filter {samAccountName -like "*"} | Where-Object {
($_.UserAccountControl -eq 544) -or ($_.UserAccountControl -eq 546) }

This formula can also be extended to accounts with the DONT_EXPIRE_PASSWORD bit.

  • 66080 = 544 (previous example) + 65536 (DONT_EXPIRE_PASSWORD)
  • 66082 = 546 (previous example) + 65536 (DONT_EXPIRE_PASSWORD)
Get-ADUser -Filter {samAccountName -like "*"} | Where-Object {
($_.UserAccountControl -eq 66080) -or ($_.UserAccountControl -eq 66082) }

Once the accounts that are in violation were identified, they were updated with the Set-ADAccountControl cmdlet. 

Additional Reading

 

Jimmy McNatt
Jimmy McNatt
Articles: 38