Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I use Windows PowerShell to determine whether or not the Guest account has been disabled on a computer?

-- RB

SpacerHey, Scripting Guy! AnswerScript Center

Hey, RB. You know, last week at this time the Scripting Guy who writes this column was on vacation, a vacation spent primarily sitting outside in the sun, only occasionally getting up to watch TV. During that week the toughest question he had to deal with was this: “Dad, are you going to make lunch or are you just going to go out and pick something up?”

Actually, that ended up being a pretty easy question to answer.

But that was then, and this is … well, not then. Last week this Scripting Guy had to decide whether he wanted to make a sandwich or just go buy a sandwich. This week he has to decide how use Windows PowerShell to determine whether or not the Guest account has been disabled on a computer. It hardly seems fair, does it?

So why is this such a difficult question to answer, at least compared to “Would you rather do some work or have someone else do the work for you?” Well, the problem is that Windows PowerShell has no built-in cmdlet for working with local user accounts. That makes working with local user accounts a little bit tricky, and has led to some surprisingly clever (albeit complicated) workarounds involving the .NET Framework. (If you don’t know what cmdlets are – or, for that matter, if you don’t know what Windows PowerShell is – then you should take a look at the Script Center’s What Can I Do With Windows PowerShell? page.)

Admittedly, in some cases those clever and complicated workarounds are required; for example, there doesn’t appear to be an easy way to change a user’s password without resorting to the .NET Framework. Fortunately, though, this isn’t one of those cases. If we want to know the status of the Guest account on the computer atl-fs-01 then we don’t have to do anything fancier than this:

Get-WmiObject Win32_UserAccount -computername "atl-fs-01" -filter "LocalAccount=True AND` 
Name='Guest'" | Select-Object Domain,Name,Disabled

Note. The Windows PowerShell commands shown in this column should all be typed on a single line.

What we’re doing here is taking advantage of the Get-WMIObject cmdlet (and the Win32_UserAccount class) in order to retrieve information about the Guest account on the computer atl-fs-01. As it turns out, Get-WMIObject works great for our purposes: it can easily return information about any and all local user accounts. We should point out, however, that it might not suit everyone’s fancy, and for at least two reasons.

For one, the –filter parameter we used works only on Windows XP and Windows Server 2003; that’s because those are the only two operating systems that support the LocalAccount property. In order to run this command on a Windows 2000 computer, you’d not only need to have Windows PowerShell installed but you’d have to modify the –filter parameter.

For another, the Win32_UserAccount class does have a few limitations, most notably the inability to set or change a user’s password. That means you can’t use this WMI class as a complete substitute for ADSI and the WinNT provider. On the bright side, however, many of the Win32_UserAccount properties are read-write, making it possible for you to do things like enable a disabled account. We won’t bother explaining this particular command in any detail, but here’s at least one way to enable the Guest account using Windows PowerShell:

$a = Get-WmiObject Win32_UserAccount -computername "atl-fs-01" -filter "LocalAccount=True AND` 
Name='Guest'"; $a.disabled=$false; $a.Put()

Note. Why did we say “at least one way” to enable the Guest account? Well, Windows PowerShell usually offers several different routes to the end goal. If you know of an alternate or – gasp! –a better way to accomplish this same task, let us know. We’ll soon be featuring alternatives/improvements to this column in a new feature we call Hey, Wait a Minute, Scripting Guy!

Caveats and cautions aside, however, the first command we showed you a minute ago should return information about the Guest account and its status. Which is all you really wanted to do anyway:

Domain             Name                        Disabled
------            	 ----                        --------
ATL-FS-01          Guest                        True

Good question: how does this command work? To begin with, we should note that we actually have two commands here, a pair of commands chained together using the Windows PowerShell pipeline (the | character). On the left-hand side of the pipeline we use the Get-WMIObject cmdlet to retrieve information from the Win32_UserAccount class. Notice that, in addition to indicating the WMI class we want to use, we also pass Get-WMIObject the following two parameters:

-computername "atl-fs-01". This, of course, is the name of the computer we’re interested in. To retrieve information for the local computer just leave this parameter out.

-filter "LocalAccount=True AND Name='Guest'". This is equivalent to the Where clause (minus the word Where) in a WQL query. As you can see, we’re simply requesting that the returned data be limited to those instances of the Win32_UserAccount class where the LocalAccount property is equal to True and the Name property is equal to Guest. Simple, huh?

The Get-WMIObject command is all we need to retrieve all the properties of the Guest account (including the Disabled property). However, it’s not enough to display all the properties of the Guest account. As it turns out, Windows PowerShell has the ability to use XML files that specify what (and how) data is displayed. By default, Windows PowerShell pre-formats many WMI classes, including Win32_UserAccount. If we only use the left-hand side of our command we’ll end up getting back something similar to this:

AccountType : 512
Caption     : ATL-FS-01\Guest
Domain      : ATL-FS-01
SID         : S-1-5-21-1292428093-1580436667-725345543-501
FullName    :
Name        : Guest

Nice, but the output doesn’t exactly tell us whether or not the account has been disabled.

But don’t despair: Windows PowerShell also provides us a number of ways to override the default formatter. For example, you retrieve the information of interest and then pipe it over to the Select-Object cmdlet; from there you can use the Select-Object cmdlet to pick out (and display) the properties of interest to you:

Select-Object Domain,Name,Disabled

Which is exactly what we did.

And so now it’s two hours until quitting time, and we’re faced with yet another tough question: get a head start on the next day’s column, or go home early? Decisions, decisions, decisions ….