As part of our data center environment, our support division is constantly processing requests for revised information regarding our customers' Windows servers. They didn't like using the WinMSD utility; which provides all possible Windows information, because they had to sort through more than 30 pages to obtain the basic information they needed (e.g., number of processors, RAM, number of hard disks).
In the Reader to Reader article “Obtain Computer Information in an Easy-to-Read Format” (InstantDoc ID 92855), I introduced an alternative: using All-Information.vbs. This script runs on a local machine and gives users a text file that contains the most commonly requested system information. Although this script is quite useful, it has limitations. So, I revised it, creating the new All-Info-MultiServer.vbs script. After I tell you what has changed, show you how to use the script and how it works.
All-Info-MultiServer.vbs includes a lot of improvements and new features. Unlike its predecessor, All-Info-MultiServer.vbs
- Accesses multiple servers. The script now uses the servers.txt file, allowing it to access multiple servers from a local desktop. Users no longer have to log on to every server individually.
- Accesses remote Windows servers through a remote procedure call (RPC) using Windows Management Instrumentation (WMI). This script obtains information from remote servers, assuming that you're in a trusted network and any firewalls connected to the remote network allow RPC connections from your location. You also need to make sure that the remote DCOM permissions aren't set to block remote connection requests and the WMI permissions allow you to make a remote connection. These settings are permitted by default.
- Outputs results into a Microsoft Excel file. The script's output is now in an Excel spreadsheet instead of individual text files. Our technical account managers have a specific set of criteria they want met in their server investigations, so I made the script reproduce that format in a comprehensive spreadsheet, with one line provided per server. If the server can't be reached in a set amount of time, the line for that server will be highlighted in yellow and contain the computer's name and the message Information Not Available. You need Excel 2000 or later on the machine if you choose to run this script.
- Determines whether any of the system processors are hyper-threading or dual-core (Intel and AMD). The script obtains information about the processor types of hyper-threading and dual-core in order to get a true processor count for the sake of proper licensing.
- Accesses RAID information for HP servers. Because of the high volume of HP servers in our data center, the script now includes HP RAID information. Windows' Disk Manager doesn't provide any information about hardware RAID configurations, so the script uses the HP Array Configuration Utility (ACU) to get true HP information. If you aren't scanning an HP server, the Windows WMI information from Disk Manager is used instead.
- Provides RAM slot locations as well as maximum RAM capacity.
- Obtains NIC connection speeds on most Windows 2000 servers. In the previous release, only Windows 2003 was supported.
- Supports Windows Server 2003 x64 Editions.
When revising the script, my goal was to have all operations contained within one .vbs file so that no external applications were needed. That way, you just need to change the script's extension from .vbs to .txt to safely transport the script via email or other media.
How to Use the Script
All-Info-MultiServer.vbs is equipped to run on Windows 2003 (32- and 64-bit), Win2K, and Windows XP (32- and 64-bit) platforms. To run this script, you need to perform several steps:
- Download All-Info-MultiServer.vbs by clicking the Download the Code Here button at the top of the page.
- Make sure Excel 2000 or later is installed on the machine running the script.
- Create a text file named servers.txt in the same directory as the script. In the text file, enter each server in the following format:
ServerID1 Domain\Username Password
ServerID2 Domain\Username Password
ServerID3 Domain\Username Password
There must be exactly one space between each of the three elements. If you already have open authentication to a remote server, you don't need to include the username or password information for that server. So, for example, if you have open authentication to ServerID2, your text file would look like
ServerID1 Domain\Username Password
ServerID3 Domain\Username Password
- Run All-Info-MultiServer.vbs. You don't need to modify this script before you use it. You can run the script under WScript or CScript.
When the script finishes running, a message box will pop up with a timestamp noting its completion time. You can then open the Scan Results.xls file, which will be in the same location as the script, in Excel to view the output.
How the Script Works
Like many other scripts, All-Info-MultiServer.vbs begins with preparations. For example, the script needs to use a shared network resource, so it uses Windows Script Host's (WSH's) root WScript object to create a WshNetwork object. The script also reads an input file (servers.txt), which it does by opening that file and writing its contents into an array. Because the script outputs its results to an Excel spreadsheet, it opens Excel, creates a workbook, and prepares a worksheet.
After All-Info-MultiServer.vbs completes those preparations, it makes several remote WMI calls. Because you only need to create the object that connects to a specific remote server once (in this case, objWMIService, as Listing 1 shows), the script will reuse that object whenever it needs to make additional remote calls. The remote connection uses the credentials in the servers.txt file for authentication, providing you don't already have open authentication to that remote server.
With the preparations complete, the real work can begin. Let's look at how some of the new features in All-Info-MultiServer.vbs work.
How the Script Determines the True Processor Count
In Windows 2003, XP, and Win2K, WMI can't natively detect hyper-threading or dual-core. Because WMI can't tell the difference between a physical processor and a logical processor, it simply doubles the processor count if hyper-threading or dual-core is enabled on a Windows server. So, to determine the true processor count, All-Info-MultiServer.vbs uses a workaround to differentiate between physical processors and logical processors.
To detect processors and determine whether they're physical or logical, the script first retrieves the values for the SocketDesignation, ProcessorID, and UniqueID properties of WMI's Win32_Processor class, as Listing 2 shows. While getting these property values along with a few others, the script obtains the number of processors in the collection returned by WMI and assigns that number to the ProcCount variable.
Next , the script calls the GetHTStatus function, which Listing 3 shows. Because the SocketDesignation, ProcessorID, and UniqueID properties are multivalued, the function assigns their values to the strNameArray, str IDArray, and strUniqueList arrays, respectively. The function then assigns the intTotal variable to zero; intTotal is one of two variables that help determine the true processor count. The other one is the intMark variable.
After the arrays are created and the intTotal variable is set to zero, the GetHTStatus function uses a main For…Next statement to get information from the arrays. In the main For…Next loop, the function first sets the intMark variable to 1. The function then takes the first socket in strNameArray and checks for three conditions:
- Redundant socket names. Because each physical processor has a unique socket name, redundant socket names means there's a logical processor. So, using the For…Next loop in callout A in Listing 3, GetHTStatus compares the first socket name against the rest of the socket names in strNameArray. If a redundant name is found, intMark is set to 0.
- Redundant globally unique identifiers (GUIDs). Because each physical processor has a GUID, redundant GUIDs means there's a logical processor. Although redundant GUIDs aren't a common occurrence, the condition must still be checked for. So, the GetHTStatus function checks the strUniqueList array for redundant GUIDs using the For…Next loop in callout B in Listing 3.
- Two processors can have the same socket name but different processor IDs. In this case, one of the two processors will have a processor ID that consists of 16 zeros, which means it has a NULL processor ID and hence is a logical processor. The For…Next loop in callout C in Listing 3 looks for NULL processor IDs. If one is found, intMark is set to 0.
After these three conditions are checked, the GetHTStatus function evaluates intMark. If intMark has a value of 1, intTotal is incremented by 1. If intMark has a value of zero, intTotal isn't incremented. The main For…Next loop then starts all over again until all the processors are evaluated.
After the evaluation is complete, the GetHTStatus function compares the count in the ProcCount variable with the value in the intTotal variable. When the ProcCount and intTotal values are equal, there are logical processors present, so the function returns the string True to the code in Listing 2. Otherwise, the function returns the string False. For an example of how this works, see Figure 1.
If the GetHTStatus function returns a True value, the code in Listing 2 proceeds in determining the processor type. When the call to the Win32_Processor class was made, Manufacturer property values were obtained and assigned to the strManuf variable. As callout A in Listing 2 shows, the code first checks the strManuf variable to see whether it contains the string Intel. If so, script lists the description as dual-core or hyper-threading. Otherwise, the description is listed as dual-core because hyper-threading technology is reserved for Intel chipsets only. Finally, the ProcCount variable's value is divided by 2 so that the true processor count is reported.
Note that Windows Vista offers the new NumberOfLogicalProcessors and NumberOfCores properties in the Win32_Processor class, so this workaround wouldn't be needed if you were writing a similar script to run on Vista. For more information about these new properties, go to the Microsoft article, "Scripting in Windows Vista: What's New in WMI?" at http://www.microsoft.com/technet/scriptcenter/topics/vista/wmi2.mspx.
How the Script Detects RAM Slot Locations and Maximum RAM Capacity
One new feature in All-Info-MultiServer.vbs is the ability to determine memory socket locations and the maximum RAM capacity on a server, regardless of Windows memory limitations (as specified per the Windows version). The MemoryBreakdown function, which Listing 4 shows, retrieves this information. First, the function calls WMI's Win32_PhysicalMemoryArray class, which represents the entire memory space. The function uses the class's MaxCapacity property to get the maximum RAM capacity and MemoryDevices property to get the total number of memory slots. The function then creates a string array with the memory slot count acting as the one-dimensional array size.
Next, the MemoryBreakdown function calls the Win32_PhysicalMemory class, which represents individual memory slots. The function uses that class's DeviceLocator, Capacity, and Speed properties to get each memory slot's location (i.e., socket or circuit board label), memory capacity, and memory speed, respectively. Because the memory capacity is in bytes, the function divides the number by 2^20 (i.e., 1,048,576) to get the number of megabytes. These three items make up a string that's set to an appropriately named array. The array's name follows the format (strPMArray(n)), where n is the trailing number in the unique identifier that the Win32_PhysicalMemoryArray class's Tag property returns for that memory device. The TrimTrailingNumber function extracts the trailing number. For example, if the Tag property value is Memory Module 1, the TrimTrailingNumber function extracts the 1 and the array is named strPMArray(1). Tag values are never redundant.
In the code at callout A in Listing 4, the MemoryBreakdown function uses a For…Next loop to determine whether there's a module in each memory slot. After trimming any leading or trailing spaces from the array's contents, the function checks the contents. If the array is empty, its value is changed to <Empty> to indicate that the slot is free. If the array isn't empty, its data (followed by a carriage return) is set to the strResult variable.
Finally, the MemoryBreakdown function appends the maximum RAM capacity value to the data in the strResult variable. However, before doing so, the function divides that value by 2^10 (i.e., 1,024) because the MaxCapacity property returned the value in kilobytes.
How the Script Accesses RAID Information for HP Servers
I would love to say that All-Info-MultiServer.vbs can simply hack into a RAID controller BIOS and extract the RAID data. However, that's not possible without a third-party application (most likely provided by the manufacturer) that can read the machine language-based instructions from that specific controller. So, I instead facilitated a workaround that utilizes the HP ACU.
The HP ACU has an executable called cpqacuxe.exe that's located (if installed by default) in the %HomeDrive%\Program Files\Compaq\Cpqacuxe\Bin folder (or “%HomeDrive%\Program Files (x86)\Compaq\Cpqacuxe\Bin” for 64-bit Windows). The script follows the command syntax
cpqacuxe.exe -c filename
to run the HP ACU. The -c switch tells the utility to run in capture mode, which means the utility will retrieve the configurations of all internal and external array controllers. The filename parameter specifies the file in which to save the captured data. In the script, the filename is c:\output.txt. The HP ACU will successfully capture the RAID configuration, provided no one else is currently using the utility. If someone else is using HP ACU, that part of the script will fail. The script will instead output the Windows' Disk Manager configuration because it’s better to have the logical information than nothing at all.
In All-Info-MultiServer.vbs, the GetHPArray function executes the HP ACU, retrieves the configuration information, then processes that information. Listing 5 shows the part of the function that executes the utility. In callout A in Listing 5, note the use of the WshNetwork2 variable. This variable creates a network connection without a drive letter to the remote file system. Although the script already has proper authentication over RPC to the remote WMI service, it needs an additional authenticated connection over Server Message Block (SMB) to interact with the file system so that it can verify the existence of the cpqacuxe.exe application and the output file. This connection also allows the script to read the output file that the HP ACU generates on the remote server.
There are a few escape procedures written into the GetHPArray function that allow a graceful failure in the event that the HP ACU doesn't exist, the output file doesn't exist, or the output file is locked (which usually indicates that the HP ACU didn't properly dump). These procedures prevent an unnecessary lag when one of these events occurs.
After the GetHPArray function retrieves the data from the output.txt file on the remote server, it stores the data in a string array named strHPParse. Using a series of string manipulation functions, the data within the strHPParse array is separated and processed. The end result is the reporting of the drive count, RAID size, RAID type, and hot-spare status.
In All-Info-MultiServer.vbs, you'll find that the GetHPArray function is fully commented so that you can see exactly how the data in the strHPParse array is manipulated. In fact, all the scripts' functions and code sections are commented in case you want to see how the rest of the script works.
Go Grab a Cup of Coffee
Although the code in All-Info-MultiServer.vbs might seem complex, using the script isn't. You just need to create an input file, then run the script. While it's doing all the work, you can go get your morning coffee.