Alternate Network Configuration Using Windows Scripting Host

This blog post is another in series about Windows Scripting Host (WSH) covering topics that have very little or no existing example code on the Internet. The challenge covered in this post is the automation of configuring the Alternate Addressing IP information on a Windows network adapter. This feature of Windows could be used in situations when a set failover configuration for TCP/IP needs to be routable or and preferred over the usual LAN only configuration provided by APIPA. Managing this for many machines using a manual process would be quite cumbersome and the following scripts will help reduce a lot of administrative effort.

The scripts made available at the end of this post are downloadable and easily modifiable. The first two posts covered building a user interface leveraging Internet Explorer and the Document Object Model through WSH, but in this post, we will shift gears and look at a unique system administration problem.

Dynamic Host Configuration Protocol (DHCP) is a service that configures TCP/IP on networked computers and devices so that they can join an IP network without manual configuration. The use of DHCP for configuration is commonplace but there are some situations where it may not be available. In these situations, Windows systems will do one of two things; it will use Automatic Private IP Addressing (APIPA) where an address in the format of 169.254.0.0/16 is automatically self-assigned or resort to an Alternate Configuration as specified for each adapter by a system administrator.

Understanding How Alternate Configuration Changes are Stored

The Alternate Configuration does not have a directly accessible interface for Windows Scripting Host, which means a little bit of engineering discovery work. For the sake of keeping this post down to a decent size the scope of the changes created are the IP address and Subnet Mask fields in the IPv4 configuration on a network adapter. Note the following example changes made in the screenshot below.

 alternative-properties

In order to get started on this task understanding what Windows does when you make changes to the Alternate Configuration tab of an adapter will be critical, so let’s will begin there. At basic level when an adapter has an Alternate Configuration like the one pictured above and the changes are applied two location in the Windows registry created or updated:

  • HKLM\System\CurrentControlSet\Services\Dhcp\Configurations\...
  • HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\...

The first location specifies a configuration to use with a naming convention of Altenate_{globally_unique_identifier}. What this would like as a full key is this:

HKLM\System\CurrentControlSet\Services\Dhcp\Configurations\Alternate_{A919B0AA-E3CD-406F-B04F-D4448ACF7A47}

This key will contain one value named Options that is a collection of binary values. The values will look like this:

registry binary value

Inside the bytes circled in red represent the octets in the IP address, which makes sense if you convert the hexadecimal value to decimal format. The bytes surrounded by the blue box are the subnet mask. The table below will help you make sense of it if you’re not already familiar with how to convert between hex and decimal base numbers.

Hex

Dec

C0

192

A8

168

00

0

01

1

FF

255

You can also see that there is a lot of data in there that we’re not concerned with. If you’re concerned with additional fields—like gateway address or DNS server assignments—the concept employed here would be extended as more bytes will appear. In my experimentation it was clear what the first 24-bytes in this registry key are for exactly, if you leave them untouched though the setting inserted in will work.

The second registry location fully expressed looks like this:

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{A919B0AA-E3CD-406F-B04F-D4448ACF7A47}

Notice that the globally unique identifier (GUID) for our network adapter is back again. Inside this registry key is a multi-string value named ActiveConfigurations which has data set to be our first registry key, which in this example is named Alternate_{A919B0AA-E3CD-406F-B04F-D4448ACF7A47}. There is that GUID again.

By editing these two registry locations we can recreate what the Windows’ Internet Protocol Version 4 (TCP/IPV4) Properties sheet does for us. It is a little bit tricky because of one of WSH’s limitations, but at this point, there is enough information to begin coding.

Getting the Adapter’s GUID

The first function to write will get a network adapter’s GUID based on the network ID displayed in Windows. As an administrator on a Windows system, the ID of the network connection is identifiable by going into the Network Connections window and looking at the name of the device. In this example, the network ID shown is Ethernet for the Intel Gigabit Network adapter.

For the function to get the GUID of the adapter, pass the Name as a parameter. The code to do this in VBscript and Jscript is below:

VBscript:

Function retrieveAdapterGuid(byVal strAdapterName)

Const wbemFlagReturnImmediately = 16
Const wbemFlagForwardOnly = 32
Set objLocator = WScript.CreateObject(“WbemScripting.SWbemLocator”)
Set objWMIService = objLocator.ConnectServer(“.”,”root\cimv2″)
objWMIService.Security_.ImpersonationLevel = 3
Set colAdapters = objWMIService.ExecQuery(“SELECT * FROM Win32_NetworkAdapter”,”WQL”, _
wbemFlagReturnImmediately Or wbemFlagForwardOnly)
For Each objAdapter In colAdapters
If UCase(objAdapter.NetConnectionID) = UCase(strAdapterName) Then
retrieveAdapterGuid = objAdapter.GUID
End If
Next

End Function

Jscript:

function retrieveAdapterGuid(strAdapterName) {

var wbemFlagReturnImmediately = 0x10;
var wbemFlagForwardOnly = 0x20;
var objLocator = WScript.CreateObject(“WbemScripting.SWbemLocator”);
var objWMIService = objLocator.ConnectServer(“.”,”root\\cimv2″);
objWMIService.Security_.ImpersonationLevel = 3;
var colItems = objWMIService.ExecQuery(“Select * from Win32_NetworkAdapter”,”WQL”,
wbemFlagReturnImmediately | wbemFlagForwardOnly);
var enumItems = new Enumerator(colItems);
for (; !enumItems.atEnd(); enumItems.moveNext()) {
if (enumItems.item().NetConnectionID == strAdapterName) {
return enumItems.item().GUID;
}
}
}

These functions connect to WMI (Windows Management Instrumentation) and queries for the list of network adapters that Windows knows about. It then loops through the list until a name match is found, when the match is found the function returns the GUID associated with that network adapter.

Writing Values to the Windows Registry Using WMI

This function is where the registry writing will happen, there will be three parameters passed into this function, the name of the IP address we want to assign, the subnet mask the connection will use, and the name of the target adapter. The logic that follows goes something like this:

  • Create the registry key Alternate_{GUID} because it may not exist already
  • Create an array with all of our generic binary values (arrays are the data type we must use to put binary and multi-string data into the registry)
  • Update cells index 20 through 23 with the values of the IP address octets
  • Update cells index 44 through 47 with the values of the subnet mask octets
  • Create the WMI connection and write the binary values to the registry
  • Create the WMI connection again and write the multi-string value to the registry

In the code that follows there are two ways of editing the registry; the first and easy way used creates the Alternate_{GUID} key using the simple WSH shell object’s regwrite method while the other two write use the WMI service to perform the write. The first method was used as it is a straight-forward method for creating a key and a value at the same time however this method cannot write more than 4-bytes to a binary value or write to a multi-string.

VBscript:

Function setAlternativeIpAddress(byVal strIpAddress,byVal strSubnetMask,byVal strAdapterName)

Const HKEY_LOCAL_MACHINE = &H80000002
Const wbemFlagReturnImmediately = 16
Const wbemFlagForwardOnly = 32
Set WshShell = WScript.CreateObject(“WScript.Shell”)
strAdapterGuid = retrieveAdapterGuid(strAdapterName)
WshShell.RegWrite “HKLM\SYSTEM\CurrentControlSet\Services\Dhcp\Configurations\Alternate_” & strAdapterGuid _
& “\Options”, &H01, “REG_BINARY”
arrIpAddress = Split(strIpAddress,”.”)
arrSubnetMask = Split(strSubnetMask,”.”)
arrBinaryValues = Array(&H32, &H00, &H00, &H00, &H00, &H00, &H00, &H00, _
&H04, &H00, &H00, &H00, &H00, &H00, &H00, &H00, _
&HFF, &HFF, &HFF, &H7F, &H00, &H00, &H00, &H00, _
&H01, &H00, &H00, &H00, &H00, &H00, &H00, &H00, _
&H04, &H00, &H00, &H00, &H00, &H00, &H00, &H00, _
&HFF, &HFF, &HFF, &H7F, &H00, &H00, &H00, &H00 )
j = 0
For i = 20 To 23
arrBinaryValues(i) = arrIpAddress(j)
j = j + 1
Next
j = 0
For i = 44 To 47
arrBinaryValues(i) = arrSubnetMask(j)
j = j + 1
Next

Set WbemLocator = WScript.CreateObject(“WbemScripting.SWbemLocator”)
Set objWmiRegistry = WbemLocator.ConnectServer(“.”,”root\default”)
Set objServices = objWmiRegistry.Get(“StdRegProv”)
Set objMethod = objServices.Methods_.Item(“SetBinaryValue”)
Set objInParam = objMethod.InParameters.SpawnInstance_()
objInParam.hDefKey = HKEY_LOCAL_MACHINE
objInParam.sSubKeyName = “SYSTEM\CurrentControlSet\Services\Dhcp\Configurations\Alternate_” & strAdapterGuid
objInParam.sValueName = “Options”
objInParam.uValue = arrBinaryValues
Set objOutParam = objServices.ExecMethod_(“SetBinaryValue”, objInParam)

arrActiveConfigurationValue = Array(“Alternate_” & strAdapterGuid)
Set WbemLocator = WScript.CreateObject(“WbemScripting.SWbemLocator”)
Set objWmiRegistry = WbemLocator.ConnectServer(“.”,”root\default”)
Set objServices = objWmiRegistry.Get(“StdRegProv”)
Set objMethod = objServices.Methods_.Item(“SetMultiStringValue”)
Set objInParam = objMethod.InParameters.SpawnInstance_()
objInParam.hDefKey = HKEY_LOCAL_MACHINE
objInParam.sSubKeyName = “SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\” & strAdapterGuid
objInParam.sValueName = “ActiveConfigurations”
objInParam.sValue = arrActiveConfigurationValue
Set objOutParam = objServices.ExecMethod_(“SetMultiStringValue”, objInParam)

End Function

Jscript:

function setAlternativeIpAddress(strIpAddress, strSubnetMask, strAdapterName) {

var HKEY_LOCAL_MACHINE = 0x80000002;
var wbemFlagReturnImmediately = 16;
var wbemFlagForwardOnly = 32;
var wshShell = WScript.CreateObject(“WScript.Shell”);
strAdapterGuid = retrieveAdapterGuid(strAdapterName);
wshShell.RegWrite(“HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Dhcp\\Configurations\\Alternate_” +
strAdapterGuid + “\\Options”, 0x01, “REG_BINARY”);
arrIpAddress = strIpAddress.split(“.”);
arrSubnetMask = strSubnetMask.split(“.”);
arrBinaryValues = new Array( 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00 );
var j = 0;
for (i = 20; i < 24; i++) {
arrBinaryValues[i] = arrIpAddress[j];
j++;
}
j = 0;
for (i = 44; i < 48; i++) {
arrBinaryValues[i] = arrSubnetMask[j];
j++;
}
var WbemLocator = WScript.CreateObject(“WbemScripting.SWbemLocator”);
var objWmiRegistry = WbemLocator.ConnectServer(“.”,”root\\default”);
var objServices = objWmiRegistry.Get(“StdRegProv”);
objMethod = objServices.Methods_.Item(“SetBinaryValue”);
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = HKEY_LOCAL_MACHINE;
objInParam.sSubKeyName = “SYSTEM\\CurrentControlSet\\Services\\Dhcp\\Configurations\\Alternate_” + strAdapterGuid + “\\”;
objInParam.sValueName = “Options”;
objInParam.uValue = arrBinaryValues;
var objOutParam = objServices.ExecMethod_(“SetBinaryValue”, objInParam);

var arrActiveConfigurationValue = new Array(“Alternate_” + strAdapterGuid);
var WbemLocator = new ActiveXObject(“WbemScripting.SWbemLocator”);
var objWmiRegistry = WbemLocator.ConnectServer(“.”,”root\\default”);
var objServices = objWmiRegistry.Get(“StdRegProv”);
objMethod = objServices.Methods_.Item(“SetMultiStringValue”);
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = HKEY_LOCAL_MACHINE;
objInParam.sSubKeyName = “SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\” + strAdapterGuid;
objInParam.sValueName = “ActiveConfigurations”;
objInParam.sValue = arrActiveConfigurationValue;
var objOutParam = objServices.ExecMethod_(“SetMultiStringValue”, objInParam);

}

In these functions, the arrBinaryValues are unwieldy and will only get worse if the other fields, like default gateway or DNS server entries, are involved. It helps to align every 8-bytes in the same way the Windows registry editor does. The sample code is intentionally laid out this way.

The Complete Scripts

The sample scripts attached bring all of these concepts together in an easy to use format. Samples will operate similarly to the example above, the Alternate Configuration for an adapter named Ethernet will be set to an IP address of 192.168.0.1. The strings assigned to the IP address, subnet mask, and adapter name can be edited to change alternate configuration of any adapter on any system.

VBscript: set alternative IP address.vbs

Jscript: set alternative IP address.js

If you have any questions please let me know in the comments.

3 Comments

  • Phil October 1, 2014 7:35 am

    Wanted to test your script so I don’t have to rewrite it, but apparently I’ll have to.

    Got an error “Object doesn’t supprt this property or method ‘objAdapter.GUID'” for line 76 car 4.

    Did I miss something ?

  • Ryan Kellerman October 2, 2014 11:15 am

    Phil —

    I had to do a little of digging on this. It looks like that WMI property for network adapters does not exist in prior to Windows Vista and Windows Server 2008. Is it possible you’re running an operating system like Windows XP or 2003?

    If so I’ll investigate another method of acquiring network adapter’s GUID for these operating systems. Although it may be time to upgrade if you can!

  • Dan Sukoneck October 7, 2014 6:41 pm

    Great job Ryan!

    It is obvious how much work you put in on this project and providing both scripts was awesome. Automation scripts can drastically improve environments and processes, but as you mentioned there is very little documentation for WSH.

    Keep up the good work!!

Your email address will not be published. Required fields are marked *

Phone: 312-602-4000
Email: marketing@westmonroepartners.com
222 W. Adams
Chicago, IL 60606
Show Buttons
Share On Facebook
Share On Twitter
Share on LinkedIn
Hide Buttons