December 8th, 2007

Hey, Scripting Guy! How Can I Map Drives Based on Membership in an Active Directory Group When the User Belongs to Multiple Groups?

Hey, Scripting Guy! Question

Hey, Scripting Guy! In yesterday’s column you showed a sample script that mapped a drive based on membership in an Active Directory group; along the way, you brought up the possibility of a user belonging to more than one group. “Suppose you have two groups,” you said. “What happens if a user is a member of both groups?” You then said, and I quote, “But that’s something we’ll have to tackle on another day. Tomorrow? We’ll see.” Well, it’s tomorrow: are you going to tackle that issue or not?

— SE

SpacerHey, Scripting Guy! AnswerScript Center

Hey, SE. By the way, in case anyone is wondering, we’re pretty sure that SE is really the Scripting Editor. How do we know that? Well, for one thing, the Scripting Guy who writes this column is a keen student of human psychology; after carefully analyzing the vocabulary and syntax found in this email he believes there’s at least a 97% chance that the message was written by the Scripting Editor.

And, besides, the Scripting Editor is currently sitting across the desk from him, brandishing her red pencil and demanding to know why the Scripting Guy who writes this column would make yet another promise to do something: “Why do you keep doing that?”

Note. As it turns out, the Scripting Editor doesn’t like it when we say, in print, that we’ll do something. Why not? Who knows; apparently that’s just the way she is. After all, look at our track record: other than the Active Directory browser (which, in our defense, we never said that we would do), we can’t think of a single thing that we said we’d do (or might do) and then never followed through on.

OK, maybe part 3 of the HTA Tutorial series. And the next installment in the Active Directory series. And – well, that’s all we can think of at the moment. If you can think of any others, please do not send us an email and let us know. We don’t need to add any fuel to the Scripting Editor’s fire.

Anyway, thanks to SE (aka the Scripting Editor ), today’s column is a continuation, of sorts, to yesterday’s Hey, Scripting Guy! As SE noted, yesterday we showed you a script that maps a drive based on the user’s membership in a particular Active Directory group. After explaining the basic script we extended the code a little, showing how you could map drive X to one share if the user was a member of group A, or map drive X to a different share if the user was a member of group B. And then we raised the question that also raised the Scripting Editor’s hackles: what do you do if a user happens to be a member of both group A and group B?

Well, as promised, here’s one solution to that problem:

On Error Resume Next

Set objDictionary = CreateObject(“Scripting.Dictionary”) Set objNetwork = CreateObject(“Wscript.Network”)

Set objADSysInfo = CreateObject(“ADSystemInfo”) strUser = objADSysInfo.UserName

Set objUser = GetObject(“LDAP://” & strUser)

For Each strGroup in objUser.memberOf Set objGroup = GetObject(“LDAP://” & strGroup) strGroupName = objGroup.CN objDictionary.Add strGroupName, strGroupName Next

If objDictionary.Exists(“Finance Managers”) Then objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\managers” Wscript.Quit End If

If objDictionary.Exists(“Finance Users”) Then objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\users” Wscript.Quit End If

If objDictionary.Exists(“Finance Planners”) Then objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\planners” Wscript.Quit End If

If objDictionary.Exists(“Finance Consultants”) Then objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\consultants” Wscript.Quit End If

And some people (we’re looking at you, “SE”) think that the Scripting Guys never keep their promises. Well, what do you think of us now, “SE”?

Really? Yikes!

Note. Although we shouldn’t be surprised; after all, editors have to know a lot of words. We just wouldn’t have guessed that SE knew words like those.

But that’s OK; sticks and stones, right? Before we dive into the details of the code, let’s quickly discuss the scenario we’re working under. For our purposes, we’re assuming we have four groups of interest in Active Directory:

Finance Managers

Finance Users

Finance Planners

Finance Consultants

The idea here is that we’re going to use a logon script to map drive X to a specified share. Which share? Well, that depends on which group the user belongs to; for example, members of the Finance Managers group will have drive X mapped to a different share than members of the Finance Users group.

So what’s the big deal? The big deal is that a user can be a member of more than one of these groups; that is, any given user could be in the Finance Managers group as well as the Finance Users, or even the Finance Planners, group.

On top of that, some groups take priority over other groups; in fact, the groups are listed in order of precedence. What does that mean? Well, suppose a user is a member of three groups: Finance Managers, Finance Users, and Finance Planners. How do we determine which share drive X gets mapped to? That’s where the order of precedence comes into play. Because Finance Managers appears at the top of the list we’ll use that group as the user’s primary group (well, their primary group for drive-mapping purposes, anyway). What if a user is a member of Finance Planners and Finance Consultants? You got it: Finance Planners takes precedence, so we’ll use Finance Planners as the primary group.

Etc., etc.

Got that? Good; then let’s get started.

The script kicks off by creating instances of the Scripting.Dictionary and Wscript.Network objects. We’ll use the Network object to map the drive. And the Dictionary object? We’ll talk about that in just a moment.

After creating these two objects, we then create a third object: ADSystemInfo, an object that enables us to grab the user’s distinguished name (DN). Once we have the DN we then bind to the user account in Active Directory and retrieve a collection of all the groups that the user belongs to. (See yesterday’s column for complete details.) After that we use the following line of code to set up a For Each loop that loops us through all the groups that the user belongs to:

For Each strGroup in objUser.memberOf

Inside this loop we use the DN for the first group to bind to the group account in Active Directory. (Again, see yesterday’s column for more information.) We then use this line of code to store the group CN in a variable named strGroupName:

strGroupName = objGroup.CN

Once we have the group CN we then add that group to our Dictionary object, using the group CN as both the Dictionary key and the Dictionary item:

objDictionary.Add strGroupName, strGroupName

What’s the point of all that? Try to be patient for another minute; we’re almost ready to talk about the details of the Dictionary object.

Before we do that, however, let’s finish talking about the For Each loop. After we’ve added the first group to the Dictionary we loop around and repeat the process with the next group in the collection. When we’re all done, we’ll have a Dictionary object that contains a list of all the groups that the user belongs to.

So why do we need to have all the groups in a Dictionary object? That’s easy: we can’t really start mapping drives until we have a list of all the groups that the user belongs to. Why not? Well, suppose we’re in the For Each loop and we discover that the user is a member of the Finance Consultants group. If we wanted to, we could go ahead and map drive X based on the user’s membership in Finance Consultants. However, that’s going to cause a problem if it turns out that the user is also a member of the Finance Users group.

To help avoid that problem, we decided to grab all the group names and put them in a Dictionary object. After the groups are safely tucked away like that we can then use the Dictionary object’s Exists method to determine whether the user is a member of a particular group. Equally important, we can check for group membership using the order of precedence.

In other words, that’s what this block of code is for:

If objDictionary.Exists(“Finance Managers”) Then
    objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\managers”
    Wscript.Quit
End If

What we’re doing here is checking to see if the string value Finance Managers appears in our Dictionary. If it doesn’t, that means that the user is not a member of Finance Managers. In that case we then skip down to the next block of code, which checks to see if the user is a member of Finance Users. (Note that we’re following the order of precedence: we’re checking for membership in Finance Managers before we check for membership in any other groups.)

Let’s assume that the value Finance Managers actually does appear in the Dictionary. That can mean only one thing: the user is a member of the Finance Managers group. In turn, we then use this line of code to map drive X to the share \\atl-fs-001\public\managers:

objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\managers”

From there we call the Wscript.Quit method to terminate the script. Why? Because the Finance Managers group takes precedence over any other group. In other words, once we’ve determined that the user is a member of Finance Managers there’s no reason to keep going; after we map a drive to \\atl-fs-001\public\managers we’re done. Notice that we also use Wscript.Quit in our next block of code:

If objDictionary.Exists(“Finance Users”) Then
    objNetwork.MapNetworkDrive “X:”, “\\atl-fs-001\public\users”
    Wscript.Quit
End If

Why? You got it: If the user is a member of Finance Users then we don’t care whether they also belong to Finance Planners or Finance Consultants. That’s because membership in Finance Users takes precedence over membership in those other two groups. Consequently, we map the drive and then terminate the script.

Etc., etc.

What if you needed to check for membership in 10 different groups? Just keep adding on these If Then blocks, making sure that you check for groups in order of precedence.

We hope that answers your … question … SE. And we hope you’ll begin to cut the Scripting Guy who writes this column a little slack, at least when it comes to making promises. After all, you know what Nikita Khrushchev once said about promises:

If we were to promise people nothing better than only revolution, they would scratch their heads and say: “Is it not better to have good goulash?”

We couldn’t have said it better ourselves.

Speaking of goulash, did someone say that it’s lunchtime? See you all tomorrow.

Author

0 comments

Discussion are closed.