How Can I Force All the Users in an OU to Change Their Password the Next Time They Log On?

Hey, Scripting Guy! How can I write a script that will force all the users in an OU to change their password the next time they log on?

-- TH

Hey, TH. You know, you picked a bad day to ask a question; the Scripting Guy who writes this column is in an even worse mood than usual (difficult as that might be to believe). A few weeks ago the Scripting Guys decided, what with the weather getting a bit better and the food in the Microsoft cafeteria getting a bit worse, that once a week they would – keep this under your hat, OK? – actually leave the campus at lunch time and go eat at a real restaurant. With that in mind, they bribed the guards, stole some uniforms from the Microsoft laundry, and dug a tunnel leading from their building across the street and into freedom.

Note. Wouldn’t it be easier to just walk out the door and go to lunch at lunchtime? Oh, sure, now you tell us.

And now that you mention it, Microsoft doesn’t actually have guards. Wonder who that was we bribed?

At any rate, today is supposed to be the day we go eat a real lunch. However, the Scripting Guys manager has called a team meeting right at the very moment the Scripting Guys had planned to enter the tunnel and make their escape. (It’s important to go at just the right moment, when the searchlights are pointed in the opposite direction and the dogs are patrolling on the other side of the campus.) That means we’re exchanging a real hamburger and fries for an update on team activities. Hurray!

Note. Aren’t team meetings an important way to get information, to foster morale, and to learn about ways to help us all do our jobs better? Hey, that’s pretty funny; it’s nice to see that someone has a sense of humor about all this.

At any rate, the Scripting Guy who writes this column is in a bad mood. Originally he was going to register his displeasure by refusing to answer TH’s question. However, that didn’t seem right; after all, TH isn’t the one who scheduled the team meeting for today. (Um, you’re not the one who scheduled the meeting for today, are you, TH?) Consequently, the Scripting Guy who writes this column opted for Plan B: he would go on a hunger strike in order to protest having a team meeting today. However, that was before he discovered that you’re not allowed to eat while on a hunger strike. (How crazy is that?) He then briefly considered going to Plan C, but coming up with yet another plan seemed like way too much work. Therefore, he decided to just answer TH’s question and be done with it:

As you can see, this is a very simple little script. (In our defense, we said we’d answer the question; we didn’t say we’d put an enormous amount of work into coming up with that answer.) To begin with, we connect to the desired OU in Active Directory; in our case, that happens to be the Accounting OU in the fabrikam.com domain:

Set objOU = GetObject("LDAP://ou=Accounting,dc=fabrikam,dc=com")

We actually get a lot of questions along these lines: how do I do something to all the user accounts/computer accounts/group accounts in an OU. People assume that this must be a very complicated task, one that requires both incredible coding skill and an intimate knowledge of Active Directory. Interestingly enough, this is actually about as easy a task as you’ll ever do. When you bind to an OU in Active Directory you, by default, get back a collection of each and every item stored in that container. If we wanted to echo back the name of each of these items all we’d have to do is set up a For Each loop and have at it:

For Each objItem in objOU
Wscript.Echo objItem.Name
Next

Of course, we aren’t interested in each and every item found in the Accounting OU; we’re only interested in user accounts. Hence the second line of code in our script:

objOU.Filter = Array("user")

What we’re doing here is applying a filter to our collection; in particular, we’re saying that we want to filter out all the objects in the collection except for user objects. What if we were interested in working with computer accounts instead? Then we’d use this filter:

objOU.Filter = Array("computer")

Pretty simple, huh? Note that you must always use an array when assigning object types to a filter, even if you only have one object in the filter. And if that makes you wonder, “Hmmm, does that mean we could put multiple objects in a single filter?” the answer is: you bet you can. For example, here’s a filter that weeds out everything except group accounts and printers (printQueue objects):

objOU.Filter = Array("group", "printQueue")

Just separate the objects with commas and you can include as many items in the filter as your heart desires.

As soon as our collection consists solely of user accounts we can go ahead and set up a For Each loop to cycle through entire set of items. Inside the loop we (automatically) bind to the first user account and then execute the following two lines of code:

objUser.pwdLastSet = 0
objUser.SetInfo

In line 1 we’re assigning the value 0 to the pwdLastSet attribute. This attribute tells us when the user last set his or her password. If the value of pwdLastSet is 0 then the user must change his or her password the next time they log on. If the user is already logged on they’ll be fine; they can continue working away without any problem. However, once they log off and then try to log back on they’ll be forced to change their password.

Note. Don’t get too excited about the pwdLastSet attribute; it really does contain the date and time the password was last changed, but the date is stored – and we are not making this up – as a large integer that “represents the number of 100 nanosecond intervals since January 1, 1601 (UTC).” If you’d like to know the date and time a password was last changed take a peek at this Hey, Scripting Guy! column.

After setting the pwdLastSet attribute to 0 we then call the SetInfo method to write the change to the actual user account in Active Directory. We then loop around and repeat the process with the next user in the collection. When we’re all done, each and every user in the Accounting OU will be required to change their password the next time they log on.

Note. OK, that might not be entirely true: this approach works only if the user has a password that expires. If any of your users have non-expiring passwords (which, we might add, is definitely not recommended) then setting pwdLastSet to 0 will have no effect on their account. But don’t worry: we just happen to have yet another Hey, Scripting Guy! column that shows you how to identify non-expiring passwords, and even how to turn them into expiring passwords.

Let’s face it: after 3+ years we have a lot of Hey, Scripting Guy! columns.

In case you’re wondering, the food at the Microsoft cafeteria really isn’t all that bad; in fact, the only problem we have with it is that they have the philosophy, “If you liked what we served you on Monday you’ll like it even better on Tuesday. And by Friday, you’ll love it!” Nevertheless, having yet another gyro sandwich is still probably better than crawling a mile or so through a dank and dark tunnel.

Probably.

P.S. For once this column has a happy ending: the team meeting ran extremely short, and the Scripting Guys managed to go out to lunch after all!