Here is the theory for building a bit-wise search: ### ### We need to scan through all users. ### ### We need to find those user's who: ### Are normal users 0x00000200 ADS_UF_NORMAL_ACCOUNT ### Are not disabled 0x00000002 ADS_UF_ACCOUNTDISABLE ### Do not have "password never expires" 0x00010000 ADS_UF_DONT_EXPIRE_PASSWD ### Do not have "no password required" 0x00000020 ADS_UF_PASSWD_NOTREQD ### ### The most efficient way to find users is to do an LDAP search. But building the ### proper search isn't that easy. We need a number of filters: ### ### objectCategory=Person ### (userAccountControl & ADS_UF_NORMAL_ACCOUNT) <> 0 ### (userAccountControl & ADS_UF_ACCOUNTDISABLE) == 0 ### (userAccountControl & ADS_UF_DONT_EXPIRE_PASSWD) == 0 ### (userAccountControl & ADS_UF_PASSWD_NOTREQD) == 0 ### ### Since userAccountControl is a BIT-FLAG attribute (meaning that individuals bits ### of the value control these options) then we need to be able to do a bit-wise ### LDAP search. It's important to realize that with a bit-wise search, the result ### of a particular filter is either not-one (!1, which is false) or not-zero (!0, ### which is true). ### ### So the next step in building our query is to use the LDAP bit-wise AND filter: ### ### 1.2.840.113556.1.4.803 ### ### This is used to do a bit-wise AND of the attribute on the left to the value ### on the right. For example: ### ### attribute:1.2.840.113556.1.4.803:=1024 ### ### This means a bit-wise AND is done of the value of the attribute to the value ### 1024 (which is 0x400 in hexadecimal). If the result of that bit-wise AND is ### zero, then the value of the filter is false. If the result is non-zero, then ### the value of the filter is true. Putting a "!" in front of a false result ### makes the result true. Putting a "!" in front of a true result, makes it false. ### ### A combination of these two techniques makes it possible to scan for zero and ### non-zero bits (that is, those which are set to one and those which are set to ### zero). ### ### LDAP also supports a bit-wise OR filter, using the special value of: ### ### 1.2.840.113556.1.4.804 ### ### Given the presence of AND and OR filters, it is possible to build very complex ### combination filters. ### ### A combination filter is built up of individual filters combined with either a ### logical OR ("|") or a logical AND ("&") and surrounded by parentheses. ### ### (& ### (objectCategory=Person) ### (userAccountControl:1.2.840.113556.1.4.803:=512) ### (!userAccountControl:1.2.840.113556.1.4.803:=2) ### (!userAccountControl:1.2.840.113556.1.4.803:=65536) ### (!userAccountControl:1.2.840.113556.1.4.803:=32) ### ) ### ### So, in pseudo-C code this is: ### ### if( ( objectCategory == Person ) AND ### ( ( userAccountControl & ADS_UF_NORMAL_ACCOUNT ) != 0 ) AND ### ( ( userAccountControl & ADS_UF_ACCOUNTDISABLE ) == 0 ) AND ### ( ( userAccountControl & ADS_UF_DONT_EXPIRE_PASSWD ) == 0 ) AND ### ( ( userAccountControl & ADS_UF_PASSWD_NOTREQD ) == 0 ) ) ### { ### ### we've got a matching user! ### } ### $ldapFilter = "(&" + "(objectCategory=Person)" + "(userAccountControl:1.2.840.113556.1.4.803:=512)" + "(!userAccountControl:1.2.840.113556.1.4.803:=2)" + "(!userAccountControl:1.2.840.113556.1.4.803:=65536)" + "(!userAccountControl:1.2.840.113556.1.4.803:=32)" + ")"
If you aren't searching, and are evaluating individual user objects, then it goes like this: $ADS_UF_NORMAL_ACCOUNT = 0x00200 $ADS_UF_ACCOUNTDISABLE = 0x00002 $ADS_UF_DONT_EXPIRE_PASSWD = 0x10000 $ADS_UF_PASSWD_NOTREQD = 0x00020 .... if( $uac -band $ADS_UF_NORMAL_ACCOUNT ) { "`t`tNormal account" } else { "`t`tNot a normal account" } if( $uac -band $ADS_UF_ACCOUNTDISABLE ) { "`t`tAccount disabled" } else { "`t`tAccount enabled" } if( $uac -band $ADS_UF_DONT_EXPIRE_PASSWD ) { "`t`tPassword doesn't expire" } else { "`t`tPassword expires" } if( $uac -band $ADS_UF_PASSWD_NOTREQD ) { "`t`tPassword not required" } else { "`t`tPassword required" } .... Obviously assuming that $uac contains the value of the userAccountControl attribute. Regards, Michael B. Smith Consultant and Exchange MVP http://TheEssentialExchange.com -----Original Message----- From: Damien Solodow [mailto:damien.solo...@harrison.edu] Sent: Wednesday, December 28, 2011 2:07 PM To: NT System Admin Issues Subject: RE: Deciphering "UserAccountControl" using PowerShell You might be over-engineering the solution. :) Try this to get a list of disabled users: Get-ADUser -Filter {enabled -eq $false} DAMIEN SOLODOW Systems Engineer 317.447.6033 (office) 317.447.6014 (fax) HARRISON COLLEGE -----Original Message----- From: Michael Leone [mailto:oozerd...@gmail.com] Sent: Wednesday, December 28, 2011 2:01 PM To: NT System Admin Issues Subject: Deciphering "UserAccountControl" using PowerShell So I know that the AD attribute "UserAccountControl" is the sum of the values of 21 different values (i.e., so a value of 546 = 2+32+512, which is composed of the sum of the constants ACCOUNT_DISABLED, PASSWORD_NOT_REQUIRED, and NORMAL_ACCOUNT). But how do I break that down in Powershell? For example, I want to do certain actions if a normal user account is disabled. However, I can't just check for a value of 514 (2+512), since - like this example - the value may be different, even tho this is an account I want to process. So how do I go about testing for ACCOUNT_DISABLED within the total value of "UserAccountControl"? (in my case, I am planning to examine user home folders, and anyone who is disabled, move them to a different holding folder. In our case, the user login is used as the name of the folder, so I just need to match the folder name with the "sAMAccountName" in AD) Thanks ~ Finally, powerful endpoint security that ISN'T a resource hog! ~ ~ <http://www.sunbeltsoftware.com/Business/VIPRE-Enterprise/> ~ --- To manage subscriptions click here: http://lyris.sunbelt-software.com/read/my_forums/ or send an email to listmana...@lyris.sunbeltsoftware.com with the body: unsubscribe ntsysadmin ~ Finally, powerful endpoint security that ISN'T a resource hog! ~ ~ <http://www.sunbeltsoftware.com/Business/VIPRE-Enterprise/> ~ --- To manage subscriptions click here: http://lyris.sunbelt-software.com/read/my_forums/ or send an email to listmana...@lyris.sunbeltsoftware.com with the body: unsubscribe ntsysadmin ~ Finally, powerful endpoint security that ISN'T a resource hog! ~ ~ <http://www.sunbeltsoftware.com/Business/VIPRE-Enterprise/> ~ --- To manage subscriptions click here: http://lyris.sunbelt-software.com/read/my_forums/ or send an email to listmana...@lyris.sunbeltsoftware.com with the body: unsubscribe ntsysadmin