Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to map a drive based on a user’s membership in a particular Active Directory group. However, I have a twist as well: I need to map a different drive depending on whether or not the user is a manager. In other words, I need to map a drive based on both group membership and job title. How do I do that?

-- SA

SpacerHey, Scripting Guy! AnswerScript Center

Hey, SA. You know, it’s been awhile since the Scripting Guy who writes this column has complained about a TV commercial. Why is that? One simple reason: the Scripting Guy who writes this column has come to his senses and no longer wastes his time watching endless hour after endless hour of TV.

No, that’s all right; we didn’t expect you to believe that anyway. The truth is, the Scripting Guy who writes this column watches as much TV as he ever has, maybe even more now that the exercise bikes at his gym all have their own TVs. (True story: Now that each exercise bike has its own TV, the Scripting Guy who writes this column has witnessed a number of people who, rather than ride the bike, simply sit on the thing and watch TV.) But have no fear: today we’re back with another in our continuing series of complaints against TV commercials. Our target this time: a new credit card commercial starring singer/actress Beyoncé.

Note to Beyoncé. If you’re reading this – and we have little doubt that you read Hey, Scripting Guy! religiously – please note that we’re not upset with you. It’s just that we don’t fully understand your latest commercial.

Speaking of which, in this commercial, Beyoncé is preparing to leave on tour. First stop? Madrid, Spain. Right before she leaves, Beyoncé promises to pick up presents for her niece and nephew. Her niece wants a kimono, and her nephew wants a boomerang.

Note to Beyoncé. Admittedly, we aren’t privy to your entire schedule. Still, if you’re bound for Madrid, Spain wouldn’t it have been better to promise to bring back something (anything!) other than a kimono or a boomerang? Having recently returned from Spain (albeit Barcelona, not Madrid), the Scripting Guy who writes this column doesn’t recall seeing very many boomerangs or kimonos for sale.

But, then again, there’s always the possibility that Beyoncé and the Scripting Guy who writes this column don’t shop at the same stores.

Hey, we didn’t say that they do shop at different stores. Just that it’s possible that they shop at different stores.

Anyway, between travel, rehearsals, photo shoots, and, well, whatever else it is that Beyoncé does, every minute of her day is booked solid. So, obviously, she forgets about her promise to her niece and nephew, doesn’t she? Heaven forbid! Not only that, but she refuses to pawn her shopping off on someone else; in fact, when an assistant asks if she should go pick up the gifts Beyoncé says, “No, I’d rather do that myself.”

And she does: she logs on to the Internet and buys her nephew a boomerang.

Now, the Scripting Guys think it’s great that a big star like Beyoncé still does her own shopping; unlike her, we’ve had our personal assistants do our shopping for us for years now. But is going online and buying a boomerang really doing your own shopping? And does buying a boomerang online truly count as bringing someone back a souvenir? The Scripting Guy who writes this column is a bit skeptical, to say the least.

Although he does like the message that this commercial sends: thanks to credit cards and the Internet, you can do all sorts of wonderful things for your family, and without having to do anything distasteful or inconvenient.

Like, you know, actually doing something for your family.

But rest assured, SA: some things in life are still done the old-fashioned way. The Scripting Guys might have their personal assistants do their shopping for them, but when it comes time to write scripts that can map drives based on membership in an Active Directory group, well, the Scripting Guys still write these themselves, using the same tools and the same techniques that their great-great grandfathers used, back in the old country. The result? This:

On Error Resume Next

Set objADSysInfo = CreateObject("ADSystemInfo")
strUser = objADSysInfo.UserName

Set objUser = GetObject("LDAP://" & strUser)

For Each strGroup in objUser.memberOf
    Set objGroup = GetObject("LDAP://" & strGroup)
    If objGroup.CN = "Finance Department" Then
        strTitle = objUser.Title
        If strTitle = "Manager" Then
            Set objNetwork = CreateObject("Wscript.Network")
            objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\managers"
        Else
            Set objNetwork = CreateObject("Wscript.Network")
            objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\users"
        End If
        Exit For
    End If     
Next

Good point; this would have been a much better gift for her nephew than a boomerang, wouldn’t it? Wonder if we can talk them into redoing that commercial?

Until then, let’s see if we can figure out how the script actually works. To begin with, we’re assuming that this script is going to run as a logon script. In fact, it pretty much has to run as a logon script; that’s because there’s no simple and straightforward method for mapping drives on remote computers.

Note. So does that mean there’s a more complicated and not-so-straightforward method for mapping drives on remote computers? Sure; hey, if you’re willing to settle for complicated and not-so-straightforward you can do almost anything. For a hint or two on how you might map a drive on a remote computer, see this Hey, Scripting Guy! column.

Because this is a logon script, we start out by creating an instance of the ADSystemInfo object, an object that returns information about the logged-on user, the local computer, and the local domain. What kind of information does ADSystemInfo return? Well, for one thing, it can tell us the DN (distinguished name) of the logged-on user. In fact, in this line of code we grab the DN for the logged-on user and store it in a variable named strUser:

strUser = objADSysInfo.UserName

As you probably know, the DN provides us with the “address” to the user’s actual Active Directory user account; that’s because the DN looks something like this:

CN=Ken Myer,OU=Europe,DC=fabrikam,DC=com

If we want to bind to that user account (and we do; that’s the only way to determine which groups the user belongs to) all we have to do is take the value of strUser, tack LDAP:// to the front of it, and then pass that value (which just happens to be the user’s ADsPath) to the Get-Object method. In other words, we just have to execute the following line of code:

Set objUser = GetObject("LDAP://" & strUser)

As you might also know, each Active Directory user account includes an attribute named memberOf; as the name implies, this attribute contains a list of all the groups that the user belongs to. That means that our next task is to cycle through that list of groups and determine whether the user is a member of a particular group (and, if he or she is, then determine whether or not the user is a manager). How are we going to do that? Well, for starters, we’re going to set up a For Each loop that walks us through each of the groups included in the memberOf attribute:

For Each strGroup in objUser.memberOf

Each group that the user belongs to is stored in the memberOf attribute by the group’s DN. (And yes, groups also have DNs; for that matter, pretty much everything in Active Directory has a DN.) Because DN’s are no fun to work with, our next step is to use this line of code to bind directly to the group account in Active Directory:

Set objGroup = GetObject("LDAP://" & strGroup)

Why do we bind to the group account? Well, as you know, what we’re doing here is looping through all the groups that the user belongs to, doing our best to determine if the user is a member of a specified group (in this case, the Finance Department group). If we wanted to, we could do this by determining if any of the user’s groups are equal to a specified DN:

If strGroup = "CN=Finance Department,OU=Finance,OU=North America,DC=fabrikam,dc=com" Then

That works, but it’s a bit cumbersome, to say the least. Therefore, to make things a bit easier on ourselves, we bind to the group account and retrieve the value of the CN attribute. In turn, that allows us to write an If-Then statement that looks like this:

If objGroup.CN = "Finance Department" Then

That’s a little easier for human beings (or even Scripting Guys, for that matter) to deal with.

Note. Another benefit to binding to the group account? When you sit down to write the script, there’s a good chance that you’ll already know the CN of the group (Finance Department). There’s probably far less chance that you’ve memorized the DNs for all your Active Directory groups. (And, if you have memorized the DNs for all your Active Directory groups, well, does the phrase “get a life” mean anything to you?)

So what if the first group in the collection doesn’t have a CN equal to Finance Department? That’s fine; in that case we simply return to the top of the loop and try again with the next group. If it turns out that none of the groups has a CN equal to Finance Department, well, that’s also fine: that just means that user isn’t a member of the Finance Department group. In that case the script simply terminates, and no drives get mapped.

Ah, but suppose one of the groups does have a CN equal to Finance Department. In that case we execute the following two lines of code:

strTitle = objUser.Title
If strTitle = "Manager" Then

In line 1, we’re simply grabbing the value of the user’s Title attribute and then storing it in a variable named strTitle; in line 2, we’re then checking to see if that title happens to be equal to Manager.

And what if the user is a manager? Well, in that case he or she will get drive X mapped to \\atl-fs-001\pubic\managers:

Set objNetwork = CreateObject("Wscript.Network")
objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\managers"

And if the user is a member of the Finance Department group but isn’t a manager? Then he or she gets a drive mapped to \\atl-fs-001\public\users instead:

Set objNetwork = CreateObject("Wscript.Network")
objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\users"

Either way, drive X gets mapped. And then we call the Exit For statement to exit the loop and bring the script to an end.

It probably goes without saying that this particular script only checks for membership in a single group (Finance Department) and then checks to see if the user is (or isn’t) a manager. However, you could easily modify the script to check for membership in other groups, or to check for other job titles. Just copy, paste, and tweak various portions of the script as needed. For example, this modified code checks to see if the user is a member of the Finance Department group or a member of the Human Resources Department group:

If objGroup.CN = "Finance Department" Then
    strTitle = objUser.Title
    If strTitle = "Manager" Then
        Set objNetwork = CreateObject("Wscript.Network")
        objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\managers"
    Else
        Set objNetwork = CreateObject("Wscript.Network")
        objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\users"
    End If
    Exit For

ElseIf objGroup.CN = "Human Resources Department" Then

    strTitle = objUser.Title
    If strTitle = "Manager" Then
        Set objNetwork = CreateObject("Wscript.Network")
        objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\hrmanagers"
    Else
        Set objNetwork = CreateObject("Wscript.Network")
        objNetwork.MapNetworkDrive "X:", "\\atl-fs-001\public\hrusers"
    End If
    Exit For

End If

You know, that’s a good question: what happens if a user is a member of both groups? Well, in that case, the user will get a drive mapping based on whichever group gets encountered first. (That is, whichever group shows up first in the For Each loop.) If that’s a problem (that is, if you’re a member of group A and a member of group B and you want group A to always take precedence), you could modify the script to keep track of all the targeted groups that the user belongs to, then write some code to pick the “best” group out of that collection. But that’s something we’ll have to tackle on another day.

Tomorrow? We’ll see.

Before we go, however, we’d like to point out that, according to published reports, Beyoncé makes approximately $18-20 million every year. Which is good news: that means that the system works. For one thing, the Scripting Guys have the moral high ground: we truly do write our own scripts, and we don’t make silly TV commercials. For another, we also make way more money each year than Beyoncé does.

Well, before taxes, anyway.