Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I remap network drives so they point to the IP address of the remote computer rather than the computer name?

-- YM

SpacerHey, Scripting Guy! AnswerScript Center

Hey, YM. You know, yesterday we started off this column by saying, “Never mind,” referring to the fact that, in a previous article, the Scripting Guy who writes this column lamented the fact that nothing interesting ever happened to him. So how are we going to start off today’s column? Like this: never mind.

Yesterday we noted that the Scripting Guy who writes this column was the … joyful … owner of a car that had experienced a “failure to proceed.” According to the preliminary diagnosis, the car had a broken ECM (which, as it turns out, is actually an ECU), and the Scripting Guy who writes this column appeared well on his way to being “the Scripting Guy who just spent several thousand dollars getting his stupid car fixed.”

Now, we should make clear that there was absolutely no question that the car was broken: even the mechanics were unable to get it to start, or even to get it to come close to starting. However, when the mechanics ran their computerized diagnostic tests everything came up just fine: apparently there was absolutely nothing wrong with the car whatsoever. (Well, aside from the fact that it wouldn’t actually start.) No matter what the mechanics tried, they couldn’t find a problem. There was nothing wrong with the car whatsoever.

Well, aside from the fact that it wouldn’t actually start.

At some point in the process one of the mechanics discovered a fuse that appeared to have burned out. This fuse is responsible for displaying warning lights on the dashboard; it has nothing to do with starting the car. And yet, once the fuse was replaced the car started right up. “It doesn’t make any sense,” said the mechanic. “I can’t tell you why that seemed to fix the problem. In fact, there’s no way that it could fix the problem. It doesn’t make any sense at all.”

And yet, so far so good. Not that the Scripting Guy who writes this column is complaining. Instead of paying out several thousands dollars, he paid $124.25: $123.00 for labor and $1.25 for parts.

Which, if you do the math, is way better than spending $2000 - $3000 to get your car fixed.

Needless to say, the Scripting Guy who writes this column felt like celebrating his good fortune. And what better way to celebrate good news than to write a script that remaps network drives so these drives point to the IP address of the remote computer rather than the computer name:

On Error Resume Next

Set objNetwork = CreateObject("Wscript.Network")
Set colDrives = objNetwork.EnumNetworkDrives

For i = 0 to colDrives.Count-1 Step 2
    strDriveLetter = colDrives.Item(i)
    strNetworkPath = colDrives.Item(i + 1)

    strNetworkPath = Replace(strNetworkPath, "\\", "")
    arrPath = Split(strNetworkPath, "\")

    strComputerName = arrPath(0)
    strFolderName = arrPath(1)

    Set objWMIService = GetObject("winmgmts:\\" & strComputerName & "\root\cimv2")

    Set colItems = objWMIService.ExecQuery _
        ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled = True")

    For Each objItem in colItems
        For Each objAddress in objItem.IPAddress
            strIPAddress = objAddress
        Next
    Next

    objNetwork.RemoveNetworkDrive strDriveLetter

    Wscript.Sleep 3000

    strNewPath = "\\" & strIPAddress & "\" & strFolderName
    objNetwork.MapNetworkDrive strDriveLetter, strNewPath
Next

Note: If you’re running this script on Windows Vista, you need to with elevated privileges for the script to work correctly. Open a command prompt by right-clicking and selecting Run As Administrator, then run your script from the command prompt.

Let’s see if we can figure out how this script works. To begin with, we should note that we started things off with the On Error Resume Next statement. Typically we don’t do that in these articles; as a general rule we leave out error-handling in order to keep the scripts a little shorter and a little easier to read. In this case, however, we occasionally got some weird errors when calling the RemoveNetworkDrive method, errors that would cause the script to crash. Why did we get those errors? Well, to tell you the truth, we aren’t really sure. But adding On Error Resume Next seemed to solve the problem, so ….

Although we assume that replacing a fuse in the Scripting Car would have solved the problem, too.

As for the real code, our next step is to create an instance of the Wscript.Network object, then use the following line to return a collection of all the mapped network drives on the computer:

Set colDrives = objNetwork.EnumNetworkDrives

The EnumNetworkDrives method does a perfectly fine job of returning all the mapped drives on a computer. However, it does so in slightly-quirky fashion: the returned information comes back as a collection that looks like this:

X:
\\atl-fs-01\public
Y:
\\atl-fs-01\users
Z:
\\atl-fs-01\scripts

As you can see, each mapped drive encompasses two items in the collection; one item (e.g., X:) representing the drive letter, the other item (\\atl-fs-01\public) representing the network path. That’s why we resort to this odd-looking For Next loop when we start iterating through the collection:

For i = 0 to colDrives.Count-1 Step 2

As you can see, we start the loop with the counter variable i equal to 0; that’s because the first item in any array or collection always has the index number 0. We end the loop when we reach the number of items in the collection (Count) minus 1. Why minus 1? Because the very last item in the collection will be the network path; for purposes of the loop, we only care about the drive letter. That’s also why we added the Step 2 parameter, which causes us to hit every other item in the collection. That way we grab only the drive letters – X:, Y:, Z: – and avoid the problem of grabbing the same drive twice (first by drive letter, the second time by network path).

Inside the loop, we start out by assigning the drive letter to a variable named strDriveLetter:

strDriveLetter = colDrives.Item(i)

We then use this line of code to assign the network path to a variable named strNetworkPath:

strNetworkPath = colDrives.Item(i + 1)

Note the index number we used here: i + 1. That’s because the network path associated with a particular drive letter will always have an index number 1 more than the drive letter. If drive Y: has the index number 2 then the path \\atl-fs-01\users will have the index number 3.

A little weird, but that’s the way it works.

Of course, the Scripting Guys know that, in order to map a drive using a computer’s IP address, it’s helpful if you actually know the computer’s IP address. One way to determine the IP address is to use the Win32_NetworkAdapterConfiguration class. Before we can use that class, however, we need to parse the computer name from the network path. That’s what this block of code is for:

strNetworkPath = Replace(strNetworkPath, "\\", "")
arrPath = Split(strNetworkPath, "\")

strComputerName = arrPath(0)
strFolderName = arrPath(1)

Let’s see if we can explain what’s going on here. To begin with, we use the VBScript Replace function to replace any instances of \\ with, well, nothing. That’s going to turn a network path like \\atl-fs-01\public into this:

atl-fs-01\public

We then use the Split function to split that value on the \ character. That results in an array named arrPath, an array consisting of the following two items:

atl-fs-01

public

We next assign item 0 (atl-fs-01) to a variable named strComputerName, then assign item 1 (public) to a variable named strFolderName. We now know two things: the name of the computer where the mapped folder resides, as well as the name of that mapped folder.

Wait a second. As it turns out, we actually know three things: we also know that we now have enough information to connect to the remote computer atl-fs-01 and determine its IP address. That’s what this block of code is for:

Set objWMIService = GetObject("winmgmts:\\" & strComputerName & "\root\cimv2")

Set colItems = objWMIService.ExecQuery _
    ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled = True")

All we’re doing here is connecting to the WMI service on the remote computer, then retrieving a collection of network adapters (using the Win32_NetworkAdapterConfiguration class). Take careful note of the Where clause we included in our query:

Where IPEnabled = True

If you query the Win32_NetworkAdapterConfiguration class without using this Where clause you’re likely to get back 10 or more network adapters; for better or worse, most of these will be virtual adapters, adapters that aren’t tied to an actual network card and don’t have an IP address. By limiting returned data to network adapters where the IPEnabled property is True we’ll only get back network adapters that do have an IP address.

That brings us to this block of code:

For Each objItem in colItems
    For Each objAddress in objItem.IPAddress
        strIPAddress = objAddress
    Next
Next

As it turns out, a network adapter can have more than one IP address; because of that the IPAddress property stores values as an array. In turn, that means that we need to use a For Each loop to get at each of these values. This block of code loops through the returned set of IP-enabled network adapters and then, for each adapter, loops through the assigned IP addresses. We have no idea of knowing which IP address is the “best” so we simply take the last address we find and assign it to a variable named strIPAddress:

strIPAddress = objAddress

At long last, we’re now ready to remap our first network drive. Except for one thing: there’s no RemapNetworkDrives method. Instead, we have to disconnect the existing drive (the one mapped using the computer name) and then create a new network drive (using the same drive letter) that maps to the IP address instead. Step 1 in that process? Disconnecting the existing drive:

objNetwork.RemoveNetworkDrive strDriveLetter

Next we use the Sleep method to pause the script for 3 seconds (3,000 milliseconds); that helps ensure that the existing drive is disconnected before we try mapping a new drive to that drive letter. After a brief pause we then create a new network path, this one using the IP address (strIPAddress) rather than the computer name:

strNewPath = "\\" & strIPAddress & "\" & strFolderName

And once we have the network path we can then call the MapNetworkDrive method and map the drive to the IP address:

objNetwork.MapNetworkDrive strDriveLetter, strNewPath

That’s going to take drive X:, which used to map to \\atl-fs-01\public, and remap it to the IP address (e.g., \\192.168.1.1\public). And then we loop around and repeat the process with the next mapped drive.

So now that the Scripting Car problems have been resolved (we hope) does that mean that the Scripting Guy who writes this column no longer needs you to send him $2,000? Heavens no; where would you get an idea like that? Granted the Scripting Car seems to be running OK, but for some reason the Scripting Guy who writes this column isn’t 100% confident that replacing a fuse that has absolutely nothing to do with the problem has somehow actually fixed the problem. And, even if it has, well, have we mentioned the fact that the Scripting Son will be headed off for college in another year? If we haven’t, don’t worry about it: no doubt you’ll have plenty of chances to hear all about that (and plenty of time to mail in your $2,000) before the big day comes. (Editor’s Note: We’re doing our best to keep the Scripting Guy’s begging to a minimum, but it’s a … challenge … to say the least. We would apologize to anyone who was feeling obligated to actually send this Scripting Guy money if we believed there was anyone like that out there.)