Skip to main content

How to Get a Users UserAccountControl Setting from Active Directory Without Using the ActiveDirectory PowerShell Module

While delivering a PowerShell class, it came to light that the users of PowerShell were not going to have access to the ActiveDirectory module.  This changes a lot.  The AD module is full of useful cmdlets to help make a Network Administrators life easier.  as a matter of fact, I did not move to PowerShell from AD administration until I PowerShell V2 and the ActiveDirectory module were available to me.

One of the more cryptic properties that can be pulled from the user account object is the UserAccountControl property.  Here is a description of the flags that can be set with this property. (Source: http://support.microsoft.com/kb/305144)

  • SCRIPT - The logon script will be run.
  • ACCOUNTDISABLE - The user account is disabled.
  • HOMEDIR_REQUIRED - The home folder is required.
  • PASSWD_NOTREQD - No password is required.
  • PASSWD_CANT_CHANGE - The user cannot change the password. This is a permission on the user's object. For information about how to programmatically set this permission, visit the following Web site:

    http://msdn2.microsoft.com/en-us/library/aa746398.aspx

  • ENCRYPTED_TEXT_PASSWORD_ALLOWED - The user can send an encrypted password.
  • TEMP_DUPLICATE_ACCOUNT - This is an account for users whose primary account is in another domain. This account provides user access to this domain, but not to any domain that trusts this domain. This is sometimes referred to as a local user account.
  • NORMAL_ACCOUNT - This is a default account type that represents a typical user.
  • INTERDOMAIN_TRUST_ACCOUNT - This is a permit to trust an account for a system domain that trusts other domains.
  • WORKSTATION_TRUST_ACCOUNT - This is a computer account for a computer that is running Microsoft Windows NT 4.0 Workstation, Microsoft Windows NT 4.0 Server, Microsoft Windows 2000 Professional, or Windows 2000 Server and is a member of this domain.
  • SERVER_TRUST_ACCOUNT - This is a computer account for a domain controller that is a member of this domain.
  • DONT_EXPIRE_PASSWD - Represents the password, which should never expire on the account.
  • MNS_LOGON_ACCOUNT - This is an MNS logon account.
  • SMARTCARD_REQUIRED - When this flag is set, it forces the user to log on by using a smart card.
  • TRUSTED_FOR_DELEGATION - When this flag is set, the service account (the user or computer account) under which a service runs is trusted for Kerberos delegation. Any such service can impersonate a client requesting the service. To enable a service for Kerberos delegation, you must set this flag on the userAccountControl property of the service account.
  • NOT_DELEGATED - When this flag is set, the security context of the user is not delegated to a service even if the service account is set as trusted for Kerberos delegation.
  • USE_DES_KEY_ONLY - (Windows 2000/Windows Server 2003) Restrict this principal to use only Data Encryption Standard (DES) encryption types for keys.
  • DONT_REQUIRE_PREAUTH - (Windows 2000/Windows Server 2003) This account does not require Kerberos pre-authentication for logging on.
  • PASSWORD_EXPIRED - (Windows 2000/Windows Server 2003) The user's password has expired.
  • TRUSTED_TO_AUTH_FOR_DELEGATION - (Windows 2000/Windows Server 2003) The account is enabled for delegation. This is a security-sensitive setting. Accounts that have this option enabled should be tightly controlled. This setting lets a service that runs under the account assume a client's identity and authenticate as that user to other remote servers on the network. 
  • PARTIAL_SECRETS_ACCOUNT - (Windows Server 2008/Windows Server 2008 R2) The account is a read-only domain controller (RODC). This is a security-sensitive setting. Removing this setting from an RODC compromises security on that server.

Here is the kicker.  This property is a single value that can represent multiple flags.  The value is stored as a decimal value, but converted to binary to determine which flags are set to true.  Each flag is represented by a power of 2”

 

Power Decimal Decimal Flag
0 0 1 SCRIPT
1 1 2 ACCOUNTDISABLE
2 10 4 HOMEDIR_REQUIRED
3 11 8 N/A
4 100 16 LOCKOUT
5 101 32 PASSWD_NOTREQD
6 110 64 PASSWD_CANT_CHANGE
7 111 128 ENCRYPTED_TEXT_PASSWORD_ALLOWED
8 1000 256 TEMP_DUPLICATE_ACCOUNT
9 1001 512 NORMAL_ACCOUNT
10 1010 1024 N/A
11 1011 2048 INTERDOMAIN_TRUST_ACCOUNT
12 1100 4096 WORKSTATION_TRUST_ACCOUNT
13 1101 8192 SERVER_TRUST_ACCOUNT
14 1110 16384 N/A
15 1111 32768 N/A
16 10000 65536 DONT_EXPIRE_PASSWD
17 10001 131072 MNS_LOGON_ACCOUNT
18 10010 262144 SMARTCARD_REQUIRED
19 10011 524288 TRUSTED_FOR_DELEGATION
20 10100 1048576 NOT_DELEGATED
21 10101 2097152 USE_DES_KEY_ONLY
22 10110 4194304 DONT_REQUIRE_PREAUTH
23 10111 8388608 PASSWORD_EXPIRED
24 11000 16777216 TRUSTED_TO_AUTH_FOR_DELEGATION
25 11001 33554432 N/A
26 11010 67108864 PARTIAL_SECRETS_ACCOUNT

The formula to figure out which flags are set is to a bit complicated.  Lets say the value of UserAccountContorl is 546.  Moving up the chart, we look for a decimal value that, if subtracted from 546, will leave a value that is greater than or equal to 0.  That number is 512.  The NORMAL_ACCOUNT flag is set.  We then take the remaining value (546 – 512 = 34).  Moving up the list, the next number that we can subtract from 34 without the result dropping below zero is 32.  The PASSWD_NOTREQD flag is set.  This leaves us with 2.  The ACCOUNTDISABLE flag is set.

Here is some code to help you out with this.  This method uses the Active Directory Services Interface [ADSI] as opposed to using the ActiveDirectory PowerShell module.

 

# get the User Account Control number.

$ObjUser = [ADSI]"LDAP://CN=User Name,DC=Domain,DC=Com"

$UAC = $ObjUser.userAccountControl

$Num = "$($UAC)"

 

$Power = 26

Do

{

    $Test = [Math]::Pow(2,$Power)

    If (($Num - $Test) -ge 0)

    {

        Switch ($Power)

        {

            26 {Write-Host "ADS_UF_PARTIAL_SECRETS_ACCOUNT"}

            24 {Write-Host "ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION"}

            23 {Write-Host "ADS_UF_PASSWORD_EXPIRED"}

            22 {Write-Host "ADS_UF_DONT_REQUIRE_PREAUTH"}

            21 {Write-Host "ADS_UF_USE_DES_KEY_ONLY    "}

            20 {Write-Host "ADS_UF_NOT_DELEGATED"}

            19 {Write-Host "ADS_UF_TRUSTED_FOR_DELEGATION"}

            18 {Write-Host "ADS_UF_SMARTCARD_REQUIRED"}

            17 {Write-Host "ADS_UF_MNS_LOGON_ACCOUNT"}

            16 {Write-Host "ADS_UF_DONT_EXPIRE_PASSWD"}

            13 {Write-Host "ADS_UF_SERVER_TRUST_ACCOUNT"}

            12 {Write-Host "ADS_UF_WORKSTATION_TRUST_ACCOUNT"}

            11 {Write-Host "ADS_UF_INTERDOMAIN_ TRUST_ACCOUNT"}

            9  {Write-Host "ADS_UF_NORMAL_ACCOUNT"}

            8 {Write-Host "ADS_UF_TEMP_DUPLICATE_ACCOUNT"}

            7 {Write-Host "ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED"}

            6 {Write-Host "ADS_UF_PASSWD_CANT_CHANGE"}

            5 {Write-Host "ADS_UF_PASSWD_NOTREQD"}

            3 {Write-Host "ADS_UF_LOCKOUT"}

            2 {Write-Host "ADS_UF_HOMEDIR_REQUIRED"}

            1 {Write-Host "ADS_UF_ACCOUNTDISABLE"}

            0 {Write-Host "ADS_UF_SCRIPT"}

        }

        $Num = $Num - $Test

    }

 

        $Power--

} While ($Power -ge 0)

Comments

Jaap Brasser said…
Hey Jason, the object that is being returned by the [adsi] connection when looking at the attributes is an ResultPropertyValueCollection. To unwrap this you can either use the array index if the attribute actually exists and it is a single value attribute. Or you could use the -join '' operator to combine this into a string.

This means that this:
$UAC = $ObjUser.userAccountControl
$Num = "$($UAC)"

Can be replaced by either one of these options:
$Num = $ObjUser.userAccountControl[0]
$Num = $ObjUser.userAccountControl -join ''

Popular posts from this blog

Adding a Comment to a GPO with PowerShell

As I'm writing this article, I'm also writing a customization for a PowerShell course I'm teaching next week in Phoenix.  This customization deals with Group Policy and PowerShell.  For those of you who attend my classes may already know this, but I sit their and try to ask the questions to myself that others may ask as I present the material.  I finished up my customization a few hours ago and then I realized that I did not add in how to put a comment on a GPO.  This is a feature that many Group Policy Administrators may not be aware of. This past summer I attended a presentation at TechEd on Group Policy.  One organization in the crowd had over 5,000 Group Policies.  In an environment like that, the comment section can be priceless.  I always like to write in the comment section why I created the policy so I know its purpose next week after I've completed 50 other tasks and can't remember what I did 5 minutes ago. In the Group Policy module for PowerShell V3, th

Return duplicate values from a collection with PowerShell

If you have a collection of objects and you want to remove any duplicate items, it is fairly simple. # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   # Remove the duplicate values. $Set1 | Select-Object -Unique 1 2 3 4 5 6 7 What if you want only the duplicate values and nothing else? # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   #Create a second collection with duplicate values removed. $Set2 = $Set1 | Select-Object -Unique   # Return only the duplicate values. ( Compare-Object -ReferenceObject $Set2 -DifferenceObject $Set1 ) . InputObject | Select-Object – Unique 1 2 This works with objects as well as numbers.  The first command creates a collection with 2 duplicates of both 1 and 2.   The second command creates another collection with the duplicates filtered out.  The Compare-Object cmdlet will first find items that are diffe

How to list all the AD LDS instances on a server

AD LDS allows you to provide directory services to applications that are free of the confines of Active Directory.  To list all the AD LDS instances on a server, follow this procedure: Log into the server in question Open a command prompt. Type dsdbutil and press Enter Type List Instances and press Enter . You will receive a list of the instance name, both the LDAP and SSL port numbers, the location of the database, and its status.