6.11.1 ProblemYou want to view the account lockout and password policies for a domain. 6.11.2 Solution6.11.2.1 Using a graphical user interface
6.11.2.2 Using a command-line interface> enumprop /ATTR:[RETURN] lockoutduration,lockoutthreshold,lockoutobservationwindow,maxpwdage,minpwdage,[RETURN] minpwdlength,pwdhistorylength,pwdproperties "LDAP://<DomainDN>" 6.11.2.3 Using VBScript' This code displays the current settings for the password ' and account lockout policies. ' ------ SCRIPT CONFIGURATION ------ strDomain = "<DomainDN>" ' e.g. rallencorp.com ' ------ END CONFIGURATION --------- set objRootDSE = GetObject("LDAP://" & strDomain & "/RootDSE") set objDomain = GetObject("LDAP://" & _ objRootDSE.Get("defaultNamingContext") ) ' Hash containing the domain password and lockout policy attributes ' as keys and the units (e.g. minutes) as the values set objDomAttrHash = CreateObject("Scripting.Dictionary") objDomAttrHash.Add "lockoutDuration", "minutes" objDomAttrHash.Add "lockoutThreshold", "attempts" objDomAttrHash.Add "lockoutObservationWindow", "minutes" objDomAttrHash.Add "maxPwdAge", "minutes" objDomAttrHash.Add "minPwdAge", "minutes" objDomAttrHash.Add "minPwdLength", "characters" objDomAttrHash.Add "pwdHistoryLength", "remembered" objDomAttrHash.Add "pwdProperties", " " ' Iterate over each attribute and print it for each strAttr in objDomAttrHash.Keys if IsObject( objDomain.Get(strAttr) ) then set objLargeInt = objDomain.Get(strAttr) if objLargeInt.LowPart = 0 then value = 0 else value = Abs(objLargeInt.HighPart * 2^32 + objLargeInt.LowPart) value = int ( value / 10000000 ) value = int ( value / 60 ) end if else value = objDomain.Get(strAttr) end if WScript.Echo strAttr & " = " & value & " " & objDomAttrHash(strAttr) next 'Constants from DOMAIN_PASSWORD_INFORMATION Set objDomPassHash = CreateObject("Scripting.Dictionary") objDomPassHash.Add "DOMAIN_PASSWORD_COMPLEX", &h1 objDomPassHash.Add "DOMAIN_PASSWORD_NO_ANON_CHANGE", &h2 objDomPassHash.Add "DOMAIN_PASSWORD_NO_CLEAR_CHANGE", &h4 objDomPassHash.Add "DOMAIN_LOCKOUT_ADMINS", &h8 objDomPassHash.Add "DOMAIN_PASSWORD_STORE_CLEARTEXT", &h16 objDomPassHash.Add "DOMAIN_REFUSE_PASSWORD_CHANGE", &h32 ' The PwdProperties attribute requires special processing because ' it is a flag that holds multiple settings. for each strFlag In objDomPassHash.Keys if objDomPassHash(strFlag) and objDomain.Get("PwdProperties") then WScript.Echo " " & strFlag & " is enabled" else WScript.Echo " " & strFlag & " is disabled" end If next 6.11.3 DiscussionSeveral parameters controlling account lockout and password complexity can be set on the Domain Security GPO. The properties that can be set for the "Account Lockout Policy" include:
The properties that can be set for the "Password Policy" include:
6.11.3.1 Using a graphical user interfaceOn a domain controller or machine that has adminpak.msi installed, the Domain Security Policy snap-in is present from the Start menu under Administrative Tools. On a member server, you need to open the GPO snap-in and locate the Domain Security policy. See Introduction in Chapter 9 for more information on GPOs. 6.11.3.2 Using a command-line interfaceThere is no standard CLI that can be used to modify a GPO, but you can use enumprop to view each of the attributes on the domain object that make up the account lockout and password policy settings. 6.11.3.3 Using VBScriptThe VBScript solution required quite a bit of code to perform a simple task; printing out the account lockout and password policy settings. First, I created a Dictionary object with each of the six attributes as the keys and the unit's designation for each key (e.g., minutes) as the value. I then iterated over each key, printing it along with the value retrieved from the domain object. Some additional code was necessary to distinguish between the values returned from some of the attributes. In the case of the time-based attributes, such as lockoutDuration, a IADsLargeInteger object was returned from the Get method instead of a pure integer or string value. IADsLargeInteger objects represent 64-bit, also known as Integer8, numbers. 32-bit systems, which make up the majority of systems today, have to break 64-bit numbers into two parts (a high and low part) in order to store them. Unfortunately, VBScript cannot natively handle a 64-bit number and stores it as a double precision. To convert a 64-bit number into something VBScript can handle, we have to first multiply the high part by 4,294,967,296 (2^32) and then add the low part to the result. value = Abs(objLargeInt.HighPart * 2^32 + objLargeInt.LowPart) Then I divided by 10,000,000 or 10^7, which represents the number of 100 nanosecond intervals per second. value = int ( value / 10000000 ) I then used the int function to discard any remainder and finally divided the result by 60 (number of seconds). value = int ( value / 60 ) Note that the result is only an approximation in minutes and can be off by several minutes, hours, or even days depending on the original value. The last part of the code iterates over another Dictionary object that contains constants representing various flags that can be set as part of the pwdProperties attribute. 6.11.4 See AlsoMS KB 221930 (Domain Security Policy in Windows 2000), MS KB 255550 (Configuring Account Policies in Active Directory), MSDN: IADsLargeInteger, and MSDN: DOMAIN_PASSWORD_INFORMATION |