Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I configure an expiration date for a local user account?

-- GW

SpacerHey, Scripting Guy! AnswerScript Center

Hey, GW. You know, it’s amazing how quickly things change in the fast-paced world of system administration scripting. For example, in Monday’s column we announced that, as time allowed and whenever possible, the Scripting Guys would include a Windows PowerShell solution in Hey, Scripting Guy! along with the VBScript solutions we typically provide people. Today, just a few days later, we’re making a new announcement: the Scripting Guys aren’t going to provide Windows PowerShell solutions after all.

Whoa, whoa settle down; let us finish. It’s true that the Scripting Guys aren’t going to provide Windows PowerShell solutions; instead we have something much better in mind: June Blender, PowerShell writer to the stars, is going to provide those solutions for us. That’s better for all of us, and for at least two reasons. First, June actually knows what she’s doing. Second, if June is doing the work then the Scripting Guy who writes this column doesn’t have to do anything at all. That part we really like.

Note. Good question: is June Blender really the PowerShell writer to the stars? To be honest, she denies that. But rumor has it that any time Tom Hanks or Cate Blanchett need a PowerShell script they contact June. And no, to the best of our knowledge, both Meryl Streep and Brad Pitt still write their own PowerShell scripts.

Admittedly, there is one drawback to this new arrangement: the fact that the Scripting Guy who writes this column typically writes it the day before it’s due to appear in the Script Center. As a matter of fact, it’s often a race to see if he can finish the column before it’s time for him to go home. (What’s that? Stay a little later so he can finish the column and then go home? You don’t know much about the Scripting Guy who writes this column, do you?) That means that the Windows PowerShell solutions will usually be added after the fact: we’ll publish a column on, say, Thursday, then add the PowerShell stuff on Friday. We’ll see if we can come up with a better way of syncing that information, but we can’t make any promises. However, we will promise to do something somewhere that will help you locate the articles that include both a VBScript solution and a Windows PowerShell solution.

In fact, June has already started adding her PowerShell solutions. Don’t believe us? Then take a peek at this column. Oh, and at this column, too. And this one. Incidentally, that last column doesn’t have any Windows PowerShell stuff in it; we just thought it was a good column.

Needless to say, the average daily scripting columnist would break June in gently, probably by choosing a question that can easily be addressed using Windows PowerShell. But the Scripting Guy who writes this column considers himself anything but average; therefore, we’re going to start off by showing you how to set the account expiration date for a local user account:

Set objUser = GetObject("WinNT://atl-ws-01/kenmyer")

objUser.AccountExpirationDate = #03/01/2008# 
objUser.SetInfo

Note to Windows Vista users: This script works only if you Run As Administrator. When you open the Command Prompt, right-click and select Run As Administrator, then run the script from that command prompt window.

As you can see, there’s hardly anything to this script, at least not the VBScript version. (What about the Windows PowerShell version? Beats us; after all, that’s not our problem.) We start off by binding to the kenmyer user account on the computer atl-ws-01. Once we’ve made the connection we then set the value of the AccountExpirationDate attribute to March 1, 2008:

objUser.AccountExpirationDate = #03/01/2008#

Why the little pound signs (#) around the date? That’s actually optional; we could have enclosed the date in double quote marks instead. However, in VBScript the pound signs specify that the value in question is a date-time value. It’s a good idea (dare we say a “best practice?”) to enclose your date-time values in pound signs; that helps guard against VBScript mistakenly viewing the value as a string, or even as a mathematical equation (e.g., 3 divided by 1 divided by 2008).

After assigning a value to the AccountExpirationDate attribute we then call the SetInfo method and officially write the change to the System Account Manager (SAM) on atl-ws-01. For those of you unfamiliar with the method, SetInfo is roughly equivalent to the Save command in an application such as Microsoft Word. You can type as much stuff into a Word document as you want, but if you never save the document then all that effort is for naught. The same is true when you use ADSI to modify attribute values. We can assign any value we want to AccountExpirationDate (or any other attribute, for that matter), but those changes do not take effect until we call SaveInfo. If the script ends without us calling SaveInfo then those changes will never take effect.

And sure, you can get a little fancy here. For example, suppose you want to give Ken Myer a temporary, 30-day account on atl-ws-01. Here’s a script that sets the expiration date to the current date plus 30 days:

Set objUser = GetObject("WinNT://atl-ws-01/kenmyer")

objUser.AccountExpirationDate = Date + 30 
objUser.SetInfo

Well, we did say a little fancy. But you get the idea.

Of course, if you’re going to go around changing account expiration dates that means that, sooner or later, you’ll need to verify those expiration dates for all the local accounts on atl-ws-01. Good thing we had this verify-account-expiration-dates script lying around, isn’t it:

On Error Resume Next

Set objAccounts = GetObject("WinNT://atl-ws-01")
objAccounts.Filter = Array("User")

For Each objUser In objAccounts
   If IsNull(objUser.AccountExpirationDate) Then
       Wscript.Echo objUser.Name, "Account has no expiration date."
   Else
       Wscript.Echo objUser.Name, objUser.AccountExpirationDate
   End If
Next

All we’re doing here is connecting to the SAM on atl-ws-01, then applying a Filter to ensure that the only items we get back are user accounts. (Otherwise we’d get back groups and printers and services and everything else known to the SAM.) After applying the filter we set up a For Each loop to loop through the entire collection of user accounts; inside that loop we use the IsNull function to identify accounts that don’t have an expiration date:

If IsNull(objUser.AccountExpirationDate) Then

If AccountExpirationDate is null we echo back a message to that effect; otherwise we echo back the user name and the account expiration date:

Wscript.Echo objUser.Name, objUser.AccountExpirationDate

The end result is something that looks like this:

Administrator Account has no expiration date.
ASPNET Account has no expiration date.
Guest Account has no expiration date.
HelpAssistant Account has no expiration date.
kenmyer 3/1/2008
pilarackerman 6/1/2007

So much for the VBScript version. As for the Windows PowerShell version, well, we’ll let June take care of that.

You know, we just thought of something: if we could find someone to write the VBScript version for us, well ….