Hey, Scripting Guy! How can I configure an Active Directory user account so that the account password never expires?
— BB
Hey, BB. Before we start we have a question for you: wouldn’t you agree that Catch-22 is one of the four greatest novels ever written? We ask that because, in his English class, the Scripting Son was recently asked to select, and read, a book from a list provided by the teacher. “Hey, Scripting Dad,” he said. “Have you read any of these books? Are any of them any good?”
“Good heavens, Scripting Son!” replied the Scripting Dad. “Catch-22 is on the list! Catch-22 is one of the four greatest novels ever written. Everyone knows that.”
“OK, I guess I’ll read that one,” replied the Scripting Son.
Of course, ever since then the Scripting Dad has had to listen to an unending litany of complaints:
• |
“This book is weird.” |
• |
“This book doesn’t make any sense.” |
• |
“I thought you said this was a good book.” |
• |
“This is all your fault.” |
Note. Actually that last one has nothing to do with Catch-22. That’s just a standard complaint the Scripting Dad hears every day. |
In order to fight fire with fire, the Scripting Dad is looking for people who agree with him that Catch-22 is one of the four greatest novels ever written. Can he count on your support, BB? OK, what if he sweetens the deal by giving you a script that can configure an Active Directory user account so that the account password never expires:
Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000Set objUser = GetObject(“LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com”)
intUserAccountControl = objUser.Get(“userAccountControl”)
If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then objUser.Put “userAccountControl”, _ objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD objUser.SetInfo End If
What do you mean, “That’s still not good enough”? Wow; you’re a tough negotiator, BB. OK, how about this: how about we explain how this script works? Deal? Deal.
As you can see, the script starts out by defining a constant named ADS_UF_DONT_EXPIRE_PASSWD and assigning this constant the hexadecimal value &h10000. We’ll need this constant when we reconfigure the account so that its password never expires.
After defining the constant we connect to the Ken Myer user account in Active Directory. Because Ken has a CN equal to Ken Myer and because his account is in the Finance OU of Fabrikam.com the code required to connect to that account looks like this:
Set objUser = GetObject(“LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com”)
Now it starts to get a little weird (but just a little). As it turns out, the Active Directory property that determines whether or not a password expires is contained within the userAccountControl property. The userAccountControl property is a “bitmask” property: that means it’s a single property that contains multiple values. Is that important? You bet it is: because userAccountControl contains multiple values we can’t simply set it to, say, True or False. Instead, we need to use “bitwise logic” to toggle the particular property that controls password expiration. That’s just a heads-up to explain why some of the code you’re about to see will look a little unusual, to say the least.
Note. We won’t to explain bitwise logic in any detail today; for more information, see this section of the Microsoft Windows 2000 Scripting Guide. |
Our next step is to determine whether or not the account already has a password that doesn’t expire; after all, if Ken already has a non-expiring password then we don’t need to do anything, do we? Using our bitwise logic we employ this line of code to determine if the “password doesn’t expire” property (represented by the constant ADS_UF_DONT_EXPIRE_PASSWD) is not enabled (notice the syntax If Not):
If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then
Like we said earlier, the userAccountControl property is actually composed of a number of different property values; for the time being, think of them as being like switches on a control panel. All we’re doing here is checking to see if the password expires switch (again, represented by the constant ADS_UF_DONT_EXPIRE_PASSWD) is on. If it is, then we’re done. If it’s not, then we need to turn it on. Bitwise logic is confusing, especially at first glance. But, at least in this case, the basic idea is simple: we take an individual switch (property) and either turn it on (enable it) or turn it off (disable it).
And that’s exactly what we do with the next two lines of code. In the first line we use the Put method to change the value of the userAccountControl in the local cache. (What’s this local cache business all about? If you aren’t sure, see this Scripting Puzzle answer for details.) Notice that we need to pass the Put method two parameters:
• |
userAccountControl, the property we want to modify. |
• |
objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD, bitwise code for “toggling” the current value of the “password doesn’t expire” property. Essentially what we’re saying here is this: if the switch (property) represented by the constant ADS_UF_DONT_EXPIRE_PASSWD is on then turn it off; if it’s off then turn it on. This is easy to do, because the XOR operator simply toggles bitwise values on and off. That’s why we had to make sure that Ken Myer’s account currently did not have a password that never expires. If he already had a non-expiring password XOR would toggle that value, thus giving him a password that did expire. |
See? Every now and then we do have a reason for doing whatever it is we do.
In the next line we call the SetInfo method to write the changes back to Active Directory. And with that, we’re done.
Of course, a lot of people might be more interested in going the other route; that is, taking an account where the password never expires and configuring it so that the password does expire. Here’s a script that does just that, checking to see if the “password never expires” property has been enabled and, if so, disables it (again, using XOR to simply toggle the value):
Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000Set objUser = GetObject(“LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com”)
intUserAccountControl = objUser.Get(“userAccountControl”)
If objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then objUser.Put “userAccountControl”, _ objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD objUser.SetInfo End If
So what do you say, BB: is that enough to get your vote that Catch-22 is one of the four greatest novels ever written? We’ll take that as a “yes.”
Note. In case you’re wondering, the other three books on the list are – as everyone knows – Sometimes a Great Notion; Night of the Hunter; and The Old Man and the Sea. And, yes, we would put Green Eggs and Ham on there, too, except we don’t think it’s officially classified as a novel. But it’s a pretty good book nonetheless. |
0 comments