From: Bart Perrier on
Up until this point I really haven't had to definitely determine the options
set by the userAccountControl. What I'm actually trying to do is determine
accounts that are enabled vs disabled.

I would expect the value of userAccountControl to be 514 for a disabled
account (http://support.microsoft.com/?id=305144). However, I can set the
account to Never Expire and the value changes to 66050 (514+65536). I'm not
sure that I can determine every possible scenario with certainty. Should I
be trying to brake the number down?

If I were to determine it manually, I would subtract the largest listed
number I can from it over and over until I can't any more. But I'm not
certain that will get me where I need either.

Does anyone have an example of working thoroughly with this property?

Bart Perrier


From: Richard Mueller [MVP] on
Bart Perrier wrote:

> Up until this point I really haven't had to definitely determine the
options
> set by the userAccountControl. What I'm actually trying to do is determine
> accounts that are enabled vs disabled.
>
> I would expect the value of userAccountControl to be 514 for a disabled
> account (http://support.microsoft.com/?id=305144). However, I can set the
> account to Never Expire and the value changes to 66050 (514+65536). I'm
not
> sure that I can determine every possible scenario with certainty. Should I
> be trying to brake the number down?
>
> If I were to determine it manually, I would subtract the largest listed
> number I can from it over and over until I can't any more. But I'm not
> certain that will get me where I need either.
>
> Does anyone have an example of working thoroughly with this property?

Hi,

userAccountControl is an integer used to flag many things. You use bit masks
to test or set bits of the number. The rule is that you "And" the value of
userAccountControl with a bit mask to test if the bit is set. Any non-zero
result means the bit is set, zero means it is not set. You "Or" with the bit
mask to set the bit, you "Xor" to toggle the bit. I coded the following
example some time ago to demonstrate all of the bit masks I found (note that
the ADS_UF_LOCKOUT flag is not reliable with LDAP):

Option Explicit

Dim objADObject, lngFlag, strObjectDN

Const ADS_UF_ACCOUNTDISABLE = &H02
Const ADS_UF_HOMEDIR_REQUIRED = &H08
Const ADS_UF_LOCKOUT = &H10
Const ADS_UF_PASSWD_NOTREQD = &H20
Const ADS_UF_PASSWD_CANT_CHANGE = &H40
Const ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = &H80
Const ADS_UF_TEMP_DUPLICATE_ACCOUNT = &H100
Const ADS_UF_NORMAL_ACCOUNT = &H200
Const ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = &H800
Const ADS_UF_WORKSTATION_TRUST_ACCOUNT = &H1000
Const ADS_UF_SERVER_TRUST_ACCOUNT = &H2000
Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Const ADS_UF_MNS_LOGON_ACCOUNT = &H20000
Const ADS_UF_SMARTCARD_REQUIRED = &H40000
Const ADS_UF_TRUSTED_FOR_DELEGATION = &H80000
Const ADS_UF_NOT_DELEGATED = &H100000
Const ADS_UF_USE_DES_KEY_ONLY = &H200000
Const ADS_UF_DONT_REQUIRE_PREAUTH = &H400000
Const ADS_UF_PASSWORD_EXPIRED = &H800000
Const ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = &H1000000

If Wscript.Arguments.Count <> 1 Then
Wscript.Echo "Required argument missing"
Wscript.Echo "Distinguished Name of user object"
Wscript.Quit
End If
strObjectDN = Wscript.Arguments(0)

On Error Resume Next
Set objADObject = GetObject("LDAP://" & strObjectDN)
If Err.Number <> 0 Then
On Error GoTo 0
Wscript.Echo "Object not found in AD: " & strObjectDN
Wscript.Quit
End If
Wscript.Echo strObjectDN

lngFlag = objADObject.Get("userAccountControl")
If Err.Number <> 0 Then
On Error GoTo 0
Wscript.Echo "Object has no userAccountControl attribute"
Wscript.Quit
End If
On Error GoTo 0

If (lngFlag And ADS_UF_ACCOUNTDISABLE) <> 0 Then
Wscript.Echo "User account disabled"
End If
If (lngFlag And ADS_UF_HOMEDIR_REQUIRED) <> 0 Then
Wscript.Echo "Home directory required"
End If
If (lngFlag And ADS_UF_LOCKOUT) <> 0 Then
Wscript.Echo "Account currently locked out"
End If
If (lngFlag And ADS_UF_PASSWD_NOTREQD) <> 0 Then
Wscript.Echo "No password required"
End If
If (lngFlag And ADS_UF_PASSWD_CANT_CHANGE) <> 0 Then
Wscript.Echo "User cannot change password"
End If
If (lngFlag And ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) <> 0 Then
Wscript.Echo "User can send an encrypted password"
End If
If (lngFlag And ADS_UF_TEMP_DUPLICATE_ACCOUNT) <> 0 Then
Wscript.Echo "Account for user in another domain (local user account)"
End If
If (lngFlag And ADS_UF_NORMAL_ACCOUNT) <> 0 Then
Wscript.Echo "Default account for typical user"
End If
If (lngFlag And ADS_UF_INTERDOMAIN_TRUST_ACCOUNT) <> 0 Then
Wscript.Echo "A ""permit to trust"" account for a domain that ""trusts""
other domains"
End If
If (lngFlag And ADS_UF_WORKSTATION_TRUST_ACCOUNT) <> 0 Then
Wscript.Echo "Computer account"
End If
If (lngFlag And ADS_UF_SERVER_TRUST_ACCOUNT) <> 0 Then
Wscript.Echo "Computer account for system backup domain controller"
End If
If (lngFlag And ADS_UF_DONT_EXPIRE_PASSWD) <> 0 Then
Wscript.Echo "Password does not expire"
End If
If (lngFlag And ADS_UF_MNS_LOGON_ACCOUNT) <> 0 Then
Wscript.Echo "MNS logon account"
End If
If (lngFlag And ADS_UF_SMARTCARD_REQUIRED) <> 0 Then
Wscript.Echo "User must logon using a smart card"
End If
If (lngFlag And ADS_UF_TRUSTED_FOR_DELEGATION) <> 0 Then
Wscript.Echo "Service account under which a service runs, trusted for
Kerberos"
End If
If (lngFlag And ADS_UF_NOT_DELEGATED) <> 0 Then
Wscript.Echo "Security context will not be delegated to a service"
End If
If (lngFlag And ADS_UF_USE_DES_KEY_ONLY) <> 0 Then
Wscript.Echo "Must use DES encryption types for keys"
End If
If (lngFlag And ADS_UF_DONT_REQUIRE_PREAUTH) <> 0 Then
Wscript.Echo "Account does not require Kerberos preauthenication for
logon"
End If
If (lngFlag And ADS_UF_PASSWORD_EXPIRED) <> 0 Then
Wscript.Echo "User password has expired"
End If
If (lngFlag And ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) <> 0 Then
Wscript.Echo "Account enabled for delegation"
End If

--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab web site - http://www.rlmueller.net
--


From: Torgeir Bakken (MVP) on
Bart Perrier wrote:

> Up until this point I really haven't had to definitely determine the options
> set by the userAccountControl. What I'm actually trying to do is determine
> accounts that are enabled vs disabled.
>
> I would expect the value of userAccountControl to be 514 for a disabled
> account (http://support.microsoft.com/?id=305144). However, I can set the
> account to Never Expire and the value changes to 66050 (514+65536). I'm not
> sure that I can determine every possible scenario with certainty. Should I
> be trying to brake the number down?
>
> If I were to determine it manually, I would subtract the largest listed
> number I can from it over and over until I can't any more. But I'm not
> certain that will get me where I need either.
>
> Does anyone have an example of working thoroughly with this property?
Hi,

Below is a modified version of the VBScript that Richard Mueller
posted in this post:
http://groups.google.co.uk/group/microsoft.public.adsi.general/msg/9eddbf0e4542c0b8?dmode=source&hl=en

The script will list all users and tell if they are disabled or not.

Run the VBScript in a command prompt (cmd.exe), like this:

cscript.exe "c:\some path\some file.vbs"

If you want to redirect the list to a file:

cscript.exe //Nologo "c:\some path\some file.vbs" >C:\some.txt


'--------------------8<----------------------

Option Explicit

Dim objConnection, objCommand, objRootDSE
Dim strDNSDomain, strFilter, strQuery, objRecordSet, strDN
Dim intFlag

Const ADS_UF_ACCOUNTDISABLE = &H02

' Use ADO to search the domain for all users.
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOOBject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

' Determine the DNS domain from the RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("DefaultNamingContext")
strFilter = "(&(objectCategory=person)(objectClass=user))"
strQuery = "<LDAP://" & strDNSDomain & ">;" & strFilter _
& ";distinguishedName,userAccountControl;subtree"

objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Cache Results") = False

' Enumerate all users. Check if account disabled.
Set objRecordSet = objCommand.Execute
Do Until objRecordSet.EOF
strDN = objRecordSet.Fields("distinguishedName")
intFlag = objRecordSet.Fields("userAccountControl")

If (intFlag And ADS_UF_ACCOUNTDISABLE) <> 0 Then
WScript.Echo "Disabled: " & strDN
Else
WScript.Echo "Enabled: " & strDN
End If
objRecordSet.MoveNext
Loop

' Clean up.
objConnection.Close

Wscript.Echo "Done"


'--------------------8<----------------------


--
torgeir, Microsoft MVP Scripting and WMI, Porsgrunn Norway
Administration scripting examples and an ONLINE version of
the 1328 page Scripting Guide:
http://www.microsoft.com/technet/scriptcenter/default.mspx
 | 
Pages: 1
Prev: Downloading SagSAS.chm
Next: Win32_ComputerSystem