Hey, Scripting Guy! I have a CAD staff that occasionally travels between sites. What I would like to do, in a logon script, is map a set of drives based on their current location, that is, their current subnet. I need the script to first check and see if the drives are already mapped; if so then the script should just leave the drives as-is. If not, I would like the drives mapped according to the current subnet. How can I do that?
Hey, GM. No doubt many of you are thinking, “As much as we enjoyed the 2008 Winter Scripting Games, now that the Games are over the Scripting Guy who writes that column will finally talk about something new for a change.” Well, you would think that, wouldn’t you? As it turns out, though, the Scripting Guy who writes this column has been so immersed in the Games for the past month or so that he truly has no idea what else is going on in the world. No idea at all.
Well, OK, except when it comes to sports; needless to say, he always finds time to keep up with – and watch – his beloved college basketball, no matter what. However, because the Washington Huskies refuse to abandon their up-and-down season on the basketball court (16 wins, 14 losses) he just doesn’t feel like talking about sports right now.
And yes, there are primary elections going on all over the US, all of them moving us closer to selecting a new President in November. But the Scripting Guy who writes this column doesn’t want to talk about politics, either. Why not? Because, by definition, someone has to win. And that hardly ever turns out to be a good thing.
Let’s see, what else is there …. Oh, here’s something he heard on TV the other day. Apparently a few years ago teachers in the United Kingdom seriously considered a proposal to change the term “failed” to “deferred success.” Get a 0 on a test? You didn’t fail; you just deferred your success to a later date. The proposal was voted down in the UK, but now people in the US are jumping on the “deferred success” bandwagon. To tell you the truth, the Scripting Guy who writes this column isn’t too keen on the idea.
And that despite the fact that no one has more deferred successes than he does.
Hey, we told you we didn’t have anything to talk about today. On the bright side, though, the 2009 Winter Scripting Games will be here before we know it. What can you do between now and then? Beats us. But you can spend at least a little time taking a look at the following script, one that maps a drive based on a computer’s current subnet:
Set objNetwork = CreateObject("Wscript.Network") strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set colAdapters = objWMIService.ExecQuery _ ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled=True") For Each objAdapter in colAdapters For Each strAddress in objAdapter.IPAddress arrOctets = Split(strAddress, ".") If arrOctets(0) <> "" Then strSubnet = arrOctets(0) & "." & arrOctets(1) & "." & arrOctets(2) x = 1 Exit For End If If x = 1 Then Exit For End If Next Next Set colItems = objWMIService.ExecQuery _ ("Select * From Win32_LogicalDisk Where DeviceID = 'H:'") If colItems.Count = 0 Then Select Case strSubnet Case "192.168.1" objNetwork.MapNetworkDrive "H:", "\\arizona-fs-01\public" Case "192.168.2" objNetwork.MapNetworkDrive "H:", "\\newmexico-fs-01\public" Case "192.168.3" objNetwork.MapNetworkDrive "H:", "\\texas-fs-01\public" End Select End If
Before we begin we should note that we’re just going to show you how to map a single drive today. But that should be no big deal; after all, to map additional drives all you need to do is:
Copy the code that checks for the existence of the drive.
Copy the code that maps the drive according to the subnet.
Change the drive letter and drive path as needed.
That should be fairly easy. Besides, the 2009 Winter Scripting Games are less than a year away; it’s never too early to start writing code and to start training.
As for the code that we wrote, we start off by creating an instance of the Wscript.Network object; this is the object that enables us to map drives using VBScript. From there we connect to the WMI service on the local computer, then use this line of code and the ExecQuery method to retrieve a collection of all the TCP/IP-enabled network adapters on the computer:
Set colAdapters = objWMIService.ExecQuery _ ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled=True")
As you know, in this day and age it’s not impossible for a computer to have more than one IP address; for example, a computer might be simultaneously connected to the network by both a wired and a wireless connection. We’re assuming that this doesn’t matter, that even if a computer does have multiple IP addresses those addresses will be on the same subnet. Admittedly, that might not be the case and, admittedly, those multiple IP addresses might make a difference. Like we said, though, we’re going to assume that this isn’t the case; instead, we’re simply going to find the first IP address on the computer and call it good.
What if that doesn’t work for you? For example, what if you want to ensure that the wired connection gets priority over the wireless connection; how do you do that? That’s something we’ll have to address in the future.
For now, we retrieve a collection of all the TCP/IP-enabled network adapters on the computer, then set up a For Each loop to loop us through each adapter in the collection:
For Each objAdapter in colAdapters
Just to complicate things even more, it’s also possible for a single network adapter to have more than one IP address; in fact, the IPAddress property in WMI’s Win32_NetworkAdapterConfiguration class is designed to store IP addresses as an array. What does that mean? That means that, to determine the IP address for a computer, we need to set up a second For Each loop, this one configured to walk us through the IP addresses assigned to a given network adapter:
For Each strAddress in objAdapter.IPAddress
Inside this second loop we use the Split method to split the IP address on the period:
arrOctets = Split(strAddress, ".")
What’s the point of that? Well, subnets are typically composed of the first 2 or 3 “octets” in an IP address (depending on your definition of a subnet). For example, the IP address 192.168.1.1 is typically considered to be on the subnet 192.168.1. An easy way to get at the first 3 octets of an IP address is to split the address into an array consisting of the following elements:
Once we have our array our next step is to use this line of code to verify that we actually have an IP address rather than an empty string:
If arrOctets(0) <> "" Then
Assuming we do, we then create a new subnet string, one consisting of the first three octets (plus the periods in between):
strSubnet = arrOctets(0) & "." & arrOctets(1) & "." & arrOctets(2)
In other words, strSubnet will now be equal to this: 192.168.1.
Just like we said we would, now that we’ve found a valid IP address we’re going to call it good. With that in mind, we set the value of a variable named x to 1, then call the Exit For statement to exit our interior For Each loop:
x = 1 Exit For
Once we’re out of the loop we check the value of x. If x is 0 that means we haven’t found an IP address yet; therefore, we go back to the top of our outside loop and try again with the next network adapter in the collection. If x is equal to 1 that means that we have found an IP address; consequently, we call the Exit For statement again, this time to exit our outside loop (the one that loops us through the collection of network adapters).
A little clunky and cumbersome, perhaps, but it works.
At this point we’re ready to map a drive (drive H), assuming that this drive isn’t already mapped somewhere else. To verify that, we run the following WMI query, a query that returns a collection of all the drives with a DeviceID (drive letter) equal to H:
Set colItems = objWMIService.ExecQuery _ ("Select * From Win32_LogicalDisk Where DeviceID = 'H:'")
After we issue the query and get back our collection, we can determine whether or not we already have a drive H simply by checking the value of the collection’s Count property, which tells us how many items (drives) are in the collection:
If colItems.Count = 0 Then
If the Count is equal to 0 that means the computer does not have a drive H; if the Count is equal to 1 then the computer does have a drive H. If the Count is equal to 1 we leave well-enough alone. If the count is equal to 0, we then check the value of strSubnet and map drive H based on that value:
Select Case strSubnet Case "192.168.1" objNetwork.MapNetworkDrive "H:", "\\arizona-fs-01\public" Case "192.168.2" objNetwork.MapNetworkDrive "H:", "\\newmexico-fs-01\public" Case "192.168.3" objNetwork.MapNetworkDrive "H:", "\\texas-fs-01\public" End Select
As you can see, if our subnet is equal to 192.168.1 we map drive H to the folder \\arizona-fs-01\public. If our subnet is equal to 192.168.2 then we map drive H to \\newmexico-fs-01\public. Etc., etc.
That should do it, GM. Incidentally, if you or anyone else had … deferred success … in the 2008 Winter Scripting Games, well, remember, the Games aren’t over until the Scripting Guys say they’re over. And we have no intention of saying that they’re over until Thursday, March 6, 2008; up until that point you can resubmit any event in which you got a 0. (And yes, that includes the Sudden Death Challenge.) Figure out what you did wrong, send us the corrected script and, assuming it works, we’ll erase that 0 and replace it with however many points we’re handing out for the event. Now that’s deferred success, eh?
It’s just too bad the Scripting Guys aren’t running college basketball. If we were, the Huskies would be doing far better than they are now. Lose a game? No problem; we’ll just let them play again until they finally get it right.