Hey, Scripting Guy! I manage over 300 servers in our environment. For each server I need to determine the members of the local Administrators account. It’s easy to get a list of local users and domain users that belong to the Admin account; it’s also easy to get a list of any domain groups that belong to the Administrators account. However, what I’d really like to do is take each of those domain groups and then get a list of their members. In other words, I don’t want to know just that the Finance Managers group has local Administrator rights; I’d like to know who belongs to the Finance Managers group (and thus has local Admin rights). Can you help?
Hey, EG. You know the Scripting Guy who writes this column is always on the lookout for weird stories. (Why? Well, for one thing, he figures that if he relates enough of these stories he might not look so weird himself.) Recently he read about a doozy of a story: a lady in Kansas who spent two years sitting on a toilet seat, refusing to get up and leave the bathroom.
Actually, that’s not the weird part. The weird part is that her boyfriend was well aware that this woman was sitting on the toilet seat refusing to get up; in fact, he brought her food and water everyday, and repeatedly urged her to come out of the bathroom. Not only that, but he was the one who eventually called the police and summoned help, albeit after two years. Why two years before he called for help? No one knows, although the Scripting Guy who writes this column can picture him warning his girlfriend, “OK, that’s fine. But if you don’t come out of the bathroom in the next two years I’m calling the police.” And, sure enough, he did.
"She is an adult; she made her own decision," said the boyfriend. "I should have gotten help for her sooner; I admit that. But after a while, you kind of get used to it."
We’ll have to take his word for that one.
Of course, just because you can get used to something doesn’t mean that you have to get used to something. For example, many of you have probably gotten used to the fact that, when you look at the members of the local Administrators group, all you can do is see that a domain group is one of the members; you can’t actually see who’s a member of that domain group. Over the years you’ve come to accept that fact.
The only problem is this: that isn’t a fact after all. As it turns out, you can see who is a member of any domain group that belongs to a local Administrators group. And in today’s column, we’re going to show you exactly how to do that.
Just as soon as the Scripting Guy who writes this column gets out of the bathroom.
OK, here we go:
strComputer = "atl-fs-001" strTestString = "/" & strComputer & "/" Set objGroup = GetObject("WinNT://" & strComputer & "/Administrators") For Each objMember In objGroup.Members If objMember.Class = "Group" Then If Not InStr(objMember.AdsPath, strTestString) Then Set objDomainGroup = GetObject(objMember.AdsPath) Wscript.Echo objDomainGroup.Name For Each objDomainMember in objDomainGroup.Members Wscript.Echo objDomainMember.FullName & " (" & objDomainMember.Name & ")" Next Wscript.Echo End If End If Next
So how does this script actually work? Well, let’s see if we can figure that out. As you can see, we start out in pretty straightforward fashion; we simply assign the name of the computer in question (atl-fs-001) to a variable named strComputer:
strComputer = "atl-fs-001"
Of course, after that promising beginning we then run smack-dab into this line of code:
strTestString = "/" & strComputer & "/"
Good question: why in the world did we insert this weird line of code? Have the Scripting Guys become a little disoriented after spending two years in a bathroom?
Of course not; the Scripting Guys don’t need to spend two years in a bathroom just to become a little disoriented. Besides, as we noted in a previous column, there is no property that makes it a snap to distinguish between a local account and an Active Directory account. Instead, the only thing you can do is to look at the ADsPath for each account. A local account will always include the computer name as part of the property value; for example:
By contrast, a domain account will feature only the name of the domain (Fabrikam):
Need to distinguish between a local account and a domain account? The easiest way that we know of to do this is to simply check to see if the computer name – enclosed in /’s – appears in the ADsPath. In our somewhat-cryptic line of code we’re simply assigning the computer name – enclosed in /’s – to the variable strTestString. In other words, strTestString will be equal to this:
Our next step is to bind to the Administrators group on the computer atl-fs-001; that’s what this line of code is for:
Set objGroup = GetObject("WinNT://" & strComputer & "/Administrators")
After we’ve made the connection to the local Administrators group we set up a For Each loop to loop us through all the members of that group (or, to make it sound like we know what we’re talking about, we loop through all the values stored in the group’s Members property):
For Each objMember In objGroup.Members
So what are we going to do inside this loop? Well, for each member of the local Administrators group we’re going to first check the value of the member’s Class attribute; that’s going to tell us whether the member is a user or a group:
If objMember.Class = "Group" Then
If the member is a user, well, who cares, right? Therefore, we simply go back to the top of the loop and repeat the process with the next group member. If the member happens to be a group, however, we need to check to make sure that /atl-fs-001/ does not appear anywhere in the ADsPath:
If Not InStr(objMember.AdsPath, strTestString) Then
If /atl-fs-001/ is found then we assume this is a local group; in that case, we go back to the top of the loop and try again with the next group member. If the target text is not found then we assume that this is a domain group; in that case, we use the following line of code – and the ADsPath – to connect to the group account in Active Directory:
Set objDomainGroup = GetObject(objMember.AdsPath)
What do we do after we make the connection to the group account? Well, for starters, we echo back the group Name:
We then set up another For Each loop, this one designed to walk through the Members of the domain group:
For Each objDomainMember in objDomainGroup.Members
Inside this loop, we echo back both the FullName and the Name (i.e., logon name) of each group member, enclosing the Name in parentheses:
Wscript.Echo objDomainMember.FullName & " (" & objDomainMember.Name & ")"
And then it’s back to the top of the loop where we start over again with the next member of the local Administrators group.
So what’s the end result of all this? Well, suppose our local Administrators group has three members (a local user, a domain user, and a domain group):
WinNT://FABRIKAM/atl-fs-001/Administrator WinNT://FABRIKAM/kenmyer WinNT://FABRIKAM/Finance Managers
When we run through the list of group members we’ll skip the Administrator account; that’s a local user account. We’ll also skip the kenmyer account; that’s a domain user account. When we hit the Finance Managers account we’ll discover that: 1) this is a group; and, 2) this is a domain account. Because of that, we’ll connect to the account in Active Directory and echo back information similar to this:
Finance Managers Jonathan Haas (jhaas) Pilar Ackerman (packerman) Syed Abbas (sabbas)
That’s all there is to it, EG. Let us know if you have any questions.
Oh, and in case you’re wondering, we did a quick check and none of the Scripting Guys have ever spent two years in a bathroom. However, we did learn that the Scripting Editor once spent two years in her office. Is that because she’s so dedicated to her job that she couldn’t bear to leave, even for a second? Possibly. However, it’s mostly because we locked the door from the outside and wouldn’t actually let her get out.
What can we say? After all, she does have a tendency to spoil all the fun around here. (Insisting that we do things right, insisting that we do everything we promised to do, etc. etc. What’s the fun in any of that?)
Editor’s Note: Had they been thinking clearly, which rarely – if ever – happens, they would have locked her out of her office, not in. But, being as dedicated to her job as she is, the Scripting Editor didn’t bother to correct them on that one.