Platform SDK: Active Directory, ADSI, and Directory Services

Modifying User Properties

Available properties of the ADSI User object vary considerably between different namespace providers. The following code will list the available properties of a particular user and their values:

Dim myUser
Dim userClass
Dim property

Set myUser = GetObject("WinNT://mymachine/username,user")
Set userClass = GetObject(myUser.Schema)

On Error Resume Next

WScript.Echo "Mandatory properties for " & myUser.Name & ":"
For Each property In userClass.MandatoryProperties
    WScript.Echo "    " & property
    WScript.Echo "      " & myUser.Get(property)
Next
WScript.Echo

WScript.Echo "Optional properties for " & myUser.Name & ":"
For Each property In userClass.OptionalProperties
    WScript.Echo "    " & property
    WScript.Echo "      " & myUser.Get(property)
Next

On Error Resume Next is used in this script to continue listing properties, even if an error occurs while attempting to retrieve a property value. The most common error in this case is error &H8000500D, which occurs when reading the value of a property that has not yet been retrieved into the local property cache.

Windows NT UserFlags

User account objects in Windows NTŪ have a UserFlags property that holds custom user properties in a bit field. Bit masking is a common programming technique which saves storage space by packing a number of Boolean values into a single number. For instance, a 16-bit integer could hold the true or false values of 16 different flags, with the value 1 representing True and 0 representing False.

Setting and reading a bit field requires combining the value of the field with a constant, or mask, using logical operators. The following code defines constants for the flags contained in the UserFlags property:

Const UF_SCRIPT                    = &H0001
Const UF_ACCOUNTDISABLE            = &H0002
Const UF_HOMEDIR_REQUIRED          = &H0008
Const UF_LOCKOUT                   = &H0010
Const UF_PASSWD_NOTREQD            = &H0020
Const UF_PASSWD_CANT_CHANGE        = &H0040
Const UF_TEMP_DUPLICATE_ACCOUNT    = &H0100
Const UF_NORMAL_ACCOUNT            = &H0200
Const UF_INTERDOMAIN_TRUST_ACCOUNT = &H0800
Const UF_WORKSTATION_TRUST_ACCOUNT = &H1000
Const UF_SERVER_TRUST_ACCOUNT      = &H2000
Const UF_DONT_EXPIRE_PASSWD        = &H10000
Const UF_MNS_LOGON_ACCOUNT         = &H20000

These constants may be combined with OR to set them in the bit field, XOR to flip the state of the specified bit, or with AND to retrieve the current state of a particular flag in the field. The following example retrieves and displays the value of the UF_LOCKOUT flag, using the constants defined earlier as bit masks:

Dim myUser

Set myUser = GetObject("WinNT://mymachine/username,user")

If myUser.UserFlags And UF_LOCKOUT Then
    WScript.Echo myUser.Name " is locked out"
Else
    WScript.Echo myUser.Name " is not locked out"
End If

The following bit of code will disable the account in the previous example and prevent the user's password from being changed:

myUser.Put "UserFlags", myUser.Flags Or UF_ACCOUNTDISABLE Or _
                                        UF_PASSWD_NOTREQD
myUser.SetInfo

Unlocking User Accounts

An account lockout policy exists on Windows NTŪ systems which will lock a user's account after a certain number of bad logon attempts. While this offers a greater level of security against a malicious intruder, it can cause headaches for a system administrator when users simply forget to turn off the Caps Lock key before entering their passwords. The following script unlocks a locked user account:

Dim myUser

Set myUser = GetObject("WinNT://mymachine/username,user")

If myUser.UserFlags And UF_LOCKOUT Then
    myUser.Put "UserFlags", myUser.Flags Xor UF_LOCKOUT
End If

Notice that this script uses an If statement to check the current value of the UF_LOCKOUT flag. If the flag is not already set, calling Xor would flip the flag to 1, which is not what the script is supposed to do. Therefore, the code checks to make sure the flag is already set to 1 before flipping it.