We're running Windows 2000 Advanced Server with Service Pack 3 (SP3). Our corporate security policy mandates that we disable Active Directory (AD) user accounts after 31 days of inactivity. I want to write an Active Directory Service Interfaces (ADSI) script that reads the value of each user's lastLogon attribute and disables the user account if that value exceeds 31 days. However, I've been unsuccessful. Can you provide some guidance?
Disabling stale user accounts by using the lastLogon attribute's value to measure staleness sounds easy enough, but unfortunately, it's not. Here's why: AD doesn't replicate the lastLogon attribute, which represents the last date and time a user was authenticated by a specific domain controller (DC). As a result, the lastLogon value will be different on each DC. To accurately determine the last date and time a user logged on, you would have to retrieve the lastLogon value from every DC in the domain, determine which of those values is the most recent, and compare that value with your inactivity threshold.
Although using the lastLogon attribute in a script is technically possible, writing this script would be difficult, especially if you have a large multidomain AD forest. But instead of using the lastLogon attribute, you can use the pwdLastSet attribute. The pwdLastSet attribute contains the date and time the corresponding user changed his or her password. Because AD replicates the pwdLastSet attribute, you can use one query to retrieve and disable all AD accounts for those users who haven't changed their password since a specific date. Admittedly, using the pwdLastSet attribute solution has one small catch. You must enable the Maximum password age password policy setting in your domain. Enabling this setting is always a good idea. Based on your corporate security policy, I suspect this requirement isn't a problem.
Here's how the pwdLastSet-based solution works. Suppose you set your domain's Maximum password age to 42 days. You can safely assume any user account's pwdLastSet attribute will contain a date within 42 days of the current date plus any time away from the office for reasons such as holidays, vacations, or leaves of absence. Let's factor in 18 days to account for time away from the office. If you query for user accounts whose pwdLastSet attribute value is less than the current date minus 60 days (42 days maximum password age policy plus 18 days for time away from the office), you should wind up with users who haven't changed their passwords in 60 days. You can then disable those inactive user accounts.
The script DisableInactiveADUsers.vbs, which Listing 1 shows, puts this theory to the test. DisableInactiveADUsers.vbs demonstrates how to use the pwdLastSet attribute to determine whether a user account is inactive and, if it is, optionally disable that account. The script supports three modes of operation: batch, interactive, and display only. In batch mode, the script automatically disables inactive accounts. In interactive mode, the script asks whether you want to disable each inactive account. The display-only mode simply displays inactive accounts on the console. The script also supports an exclusion list to ensure that special-purpose accounts aren't inadvertently disabled. Let's walk through DisableInactiveADUsers.vbs to see how it works.
Like many Windows Script Host (WSH)/VBScriptbased systems administration scripts, DisableInactiveADUsers.vbs starts by enabling Option Explicit and declaring all the script's variables. Next, the script defines the three constants (i.e., BATCH_MODE, INTERACTIVE_MODE, and DISPLAY_ONLY_MODE) that identify the script's three modes of operation. I discuss these constants shortly.
At callout A in Listing 1, the script uses the MAXIMUM_PASSWORD_AGE constant to set the script's inactive threshold. As the constant's name suggests, MAXIMUM_PASSWORD_AGE is the maximum password age in days. Users who haven't changed their passwords within the specified number of days are considered inactive, and their accounts are subject to being disabled. The value you assign to the MAXIMUM_PASSWORD_AGE constant must not be less than your domain's Maximum password age policy setting. Otherwise, you might disable active accounts.
At callout B, the script uses the BATCH_MODE, INTERACTIVE_MODE, or DISPLAY_ONLY_MODE constant to set the mode of operation. The script's default mode is DISPLAY_ONLY_MODE. Setting the intMode variable to INTERACTIVE_MODE or BATCH_MODE will change the script's behavior accordingly.
At callout C, the script creates a Dictionary object named objExclusions to hold the names of special-purpose user accounts that are excluded from the disable operation. If any of the user accounts stored in objExclusions are inactive, the script reports them as inactive, but you'll have to disable them manually.