Documenting Specs of Existing Windows Servers

by techpilot007 15. May 2012 23:56

Every month we receive a bill from our Sister Company for the hosting of our servers. When we receive the bill we usually just check our records to see that the specs we have documented match what we are being billed for. This tedious task falls to our Director of Infrastructure.

Since I started 7 months ago he has seen the power or scripting on Windows from the rough scripts I wrote in vbScript to gather IIS, HTTP information about our existing environment and the power of scripts being used to monitor our systems. So you can see where I am going with this. He asked on a Thursday afternoon if it were possible and if I had time to write him a script that would go out to our Windows servers and gather the specs that we incur charges for (CPU cores, Memory in GB, HDD in GB).

As with all the scripts I write I take a look at what others have already done so that I don't recreate the wheel. I happened to find one script that would look at a single server and dump it's information in an excel file. The first thing I didn't like about this script was how the server information in the spreadsheet was placed vertically in the file meaning that column A was the field headings and column B was the server information. So I set about modifying the script to display the information in a horizontal fashion.

The second thing that bothered me about this script was that it only worked for one server that you had to manually set in the script before you ran it. Manually editing the script every time it ran to get information on a different server was not something I could tolerate so how could anyone else. So I set about hacking apart some old scripts that I had created when I started 7 months ago. The result was a script that could read a text file filled with server names and reach out to them placing their information in the excel file. The text file looked like this:


At this point I decided I would customize what I was looking for. The script I originally started with was grabbing the bios information. Frankly for what we need to know the Bios information was unnecessary along with a few other specs. I then came to realize that the hard disk information was not in this script. Luckily I had another script that I could use code from to accomplish this task (a vbScript that I wrote to grab HDD info for Nagios).

After all of that I thought I was done since it was working on every box I tried it on. So I sent it on to the Director. I had finished the script by noon on the Monday following his initial request. The first time he ran it he received an error. I was stumped at first but then came to realize that he didn't have access to one of the servers in his list. As with anything you find broken it's best to fix it when you find so you don't forget about it. I wanted the script to continue to execute for the rest of the servers in the list with only making note in the table that it was unable to access/find the server. With this new requirement I set about adding two functions that try to find the server and then checks to see that it has permission to get information on that server. If either of those two functions fails then the reason for failure is listed in the spreadsheet and the script moves on to the next server.

My completed script looked like this:

Dim strCompList
Dim strComputer
Const ForReading = 1

strComputer = ""
strCompList = "WindowsServers.txt"

IF WScript.Arguments.Length >= 1 THEN
    strSiteList = WScript.Arguments( 0 )

Set objFSO = CreateObject("Scripting.FileSystemObject")
sCurPath = unescape(objFSO.GetAbsolutePathName(".") & "\")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile (sCurPath & strCompList, ForReading)
strText = objTextFile.ReadAll

strFileName = year(date) & "-" & month(date) & "-" & Day(Date) & "_" & Hour(Now()) & Minute(Now()) & ".xls"

arrComputers = Split(strText, vbCrLf)

Set objExcel = CreateObject("Excel.Application")

objExcel.Visible = True

'Name the columns
objExcel.Cells(1, 1).Value = "Name"
objExcel.Cells(1, 2).Value = "Caption"
objExcel.Cells(1, 3).Value = "Version" 
objExcel.Cells(1, 4).Value = "Serial Number" 
objExcel.Cells(1, 5).Value = "Description" 
objExcel.Cells(1, 6).Value = "Domain" 
objExcel.Cells(1, 7).Value = "Manufacturer" 
objExcel.Cells(1, 8).Value = "Model" 
objExcel.Cells(1, 9).Value = "Number Of Processors" 
objExcel.Cells(1, 10).Value = "System Type" 
objExcel.Cells(1, 11).Value = "Total Physical Memory" 
objExcel.Cells(1, 12).Value = "HDD Space"

intDataRow = 1

For Each strComputer in arrComputers

	Dim intGigs
	Dim intCapUsed
	Dim intCapSize
	Dim intCapFree
	Dim intPerCapUsed
	Dim strDeviceInfo
	Dim strAllDeviceInfo
	intGigs = 1073741824
	intCapUsed = 0
	intCapSize = 0
	intCapFree = 0
	intPerCapUsed = 0
	strDeviceInfo = ""
	strAllDeviceInfo = ""

	intDataRow = intDataRow + 1

	If Ping(strComputer) Then
		If Permission(strComputer) Then
			Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
			Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
			For Each objItem in colItems
			objExcel.Cells(intDataRow, 1).Value = objItem.CSName
			objExcel.Cells(intDataRow, 2).Value = objItem.Caption
			objExcel.Cells(intDataRow, 3).Value = objItem.Version
			objExcel.Cells(intDataRow, 4).Value = objItem.SerialNumber
			objExcel.Cells(intDataRow, 5).Value = objItem.Description


			Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem")
			For Each objItem in colItems
			objExcel.Cells(intDataRow, 6).Value = objItem.Domain
			objExcel.Cells(intDataRow, 7).Value = objItem.Manufacturer
			objExcel.Cells(intDataRow, 8).Value = objItem.Model
			objExcel.Cells(intDataRow, 9).Value = objItem.NumberOfProcessors
			objExcel.Cells(intDataRow, 10).Value = objItem.SystemType
			objExcel.Cells(intDataRow, 11).Value = FormatNumber((objItem.TotalPhysicalMemory / intGigs),2) & " GB"


			Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
			Set colDisks = objWMIService.ExecQuery("select * from Win32_LogicalDisk where DriveType='3'")
			For Each objDisk in colDisks
			intCapSize = objDisk.Size / intGigs
			intCapFree = objDisk.Freespace / intGigs
			intCapUsed = intCapSize - intCapFree
			intPerCapUsed = (intCapUsed / intCapSize) * 100
				if IsNull(intPerCapUsed) Then
					intPerCapUsed = CInt(0)
					intPerCapUsed = CInt((intCapUsed / intCapSize) * 100)
				end if
				if IsNumeric(intCapSize) Then
					intCapSize = FormatNumber(intCapSize,2)
				end if
				if IsNumeric(intCapUsed) Then
					intCapUsed = FormatNumber(intCapUsed,2)
				end if
			strDeviceInfo = objDisk.DeviceID & " (Used " & intCapUsed & " GB of " & intCapSize & " GB)"

			if strAllDeviceInfo <> "" Then
				strAllDeviceInfo =  strDeviceInfo & ", " & strAllDeviceInfo
				strAllDeviceInfo = strDeviceInfo
			end if

			objExcel.Cells(intDataRow, 12).Value = strAllDeviceInfo
			intDataColumns = 1
			objExcel.Cells(intDataRow, 1).Value = strComputer
			objExcel.Cells(intDataRow, 2).Value = "Time out or Permission Denied"
			For intDataColumns = 3 to 12
				objExcel.Cells(intDataRow, intDataColumns).Value = "N/A"
		End If
		intDataColumns = 1
		objExcel.Cells(intDataRow, 1).Value = strComputer
		objExcel.Cells(intDataRow, 2).Value = "Cannot Find Server"
		For intDataColumns = 3 to 12
			objExcel.Cells(intDataRow, intDataColumns).Value = "N/A"
	End If


objExcel.Selection.Font.ColorIndex = 11
objExcel.Selection.Font.Bold = True
objExcel.DefaultFilePath = sCurPath
objExcel.ActiveWorkBook.SaveAs strFileName, -4143

MsgBox "Done"

Function Ping(Target)
Dim results

    On Error Resume Next

    Set shell = CreateObject("WScript.Shell")
    ' Send 1 echo request, waiting 2 seconds for result 
    Set exec = shell.Exec("ping -n 1 -w 2000 " & Target)
    results = LCase(exec.StdOut.ReadAll)
    Ping = (InStr(results, "reply from") > 0)
End Function

Function Permission(strServer)
Dim objWMIService
	' Err.Clear ' redundant code
	' VBScript calls the Clear method automatically whenever On Error Resume Next statement is executed
	On Error Resume Next
	Set objWMIService = GetObject("winmgmts:\\" & strServer & "\root\CIMV2")

	Select Case Err.Number
	  Case 0
		' Success
		Permission = True
	  Case 70
		' Run-time error '70': Permission denied
		Permission = False
	  Case 462
		' The remote server machine does not exist or is unavailable
		Permission = False
	  Case -2147217375
		' Unknown/undocumented runtime error (till this time)
		' The remote server machine name was assigned erroneously
		Permission = False
		'Wscript.echo ">>" & strServer & "<<", "Run-time error '-2147217375' (undocumented runtime error)", "Error # " & CStr(Err.Number)
	  Case Else
		' Unhandled Run-time error (till this time)
		Permission = False
		'Wscript.echo ">>" & strServer & "<<", "Unhandled Run-time error # " & CStr(Err.Number) & " " & Err.Description
	End Select
	On Error GoTo 0
End Function
Comments are closed


Welcome to the blog of an Configuration Manager. This blog is meant to share my thoughts, ideas, and the story of my ever expanding journey to acquire knowledge. It may, at times, include rants about or an expression of excitement over something in the computer realm. The majority of my work is with Windows servers. However, it has started to also include Linux machines. Lately I’ve become the Nagios “expert” within our company as I work towards creating culture of being proactive vs. reactive in regards to Application/Configuration Management.


(The information in this blog is provided “AS IS” with no warranties, and confers no rights implied or otherwise. The views, opinions, and ideas, expressed here are my own, and may not necessarily represent the views and opinions of my employer, past, current, or future.)



<<  December 2017  >>

View posts in large calendar