January 23, 2010
I will say up front that this example is a bit complicated – if you feel sick to your stomach after reading this article it is not my fault. So, what does this example show:
- Query Active Directory using ADO to obtain a list of all computers on the domain.
- Ping each of the computers to verify that the computer may be reached over the network.
- Send a WMI query to each computer that responded to a ping. The WMI query targets Win32_ComputerSystem which describes the timezone, domain, computer role, computer manufacturer, computer model, number of CPUs, amount of physical memory, currently logged on user, and more.
- Create a table in the Oracle database to contain the data returned by the WMI query (using a very generic VARCHAR2(100) definition for each column).
- Transfer the data from the WMI results to the database table.
- Announce using voice prompts if a computer does not respond to a ping, and also announce when the WMI query is being sent to the remote computer.
Note that I had a bit of difficulty making the usual method for submitting SQL statements with bind variables work correctly with the WMI data, so I used another approach. There are 2 subroutines in the script, the Main script is started when the VBS file executes, and the Main script calls the PingTest function as needed. Save the script as CheckComputers.vbs, then execute the script using either cscript or wscript. Note that you must be an aministrator on each computer, or a domain administrator for the remote WMI queries to correctly execute.
Main
Sub Main()
Const CONVERT_TO_LOCAL_TIME = True
Const wbemFlagReturnImmediately = &H10
Const wbemFlagForwardOnly = &H20
Const adCmdText = 1
Const adVarChar = 200
Const adchar = 129
Const adParamInput = 1
Const adOpenKeyset = 1
Const adLockOptimistic = 3
Const ADS_SCOPE_SUBTREE = 2
Dim strSpeech
Dim objSpeech
Dim strComputer
Dim varStartTime
Dim objWMIService
Dim colItems
Dim objItem
Dim i
Dim intResult
Dim intComputer
Dim lngPass
Dim lngPassMax
Dim intColumns
Dim intColumn
Dim objProperty
Dim dbActiveDirectory
Dim strSQL
Dim strSQLInsert
Dim strSQLTable
Dim comData
Dim snpData
Dim strDomain
Dim comDataInsert
Dim dynDataInsert
Dim dbDatabase
Dim strUsername
Dim strPassword
Dim strDatabase
On Error Resume Next
Set dbDatabase = CreateObject("ADODB.Connection")
Set comDataInsert = CreateObject("ADODB.Command")
Set dynDataInsert = CreateObject("ADODB.Recordset")
Set objSpeech = CreateObject("SAPI.SpVoice")
strUsername = "MyUsername"
strPassword = "MyPassword"
strDatabase = "MyDB"
strDomain = "DC=oracle,DC=com" 'Your domain: Equivalent to oracle.com, change as needed
Set dbActiveDirectory = CreateObject("ADODB.Connection")
Set comData = CreateObject("ADODB.Command")
Set snpData = CreateObject("ADODB.Recordset")
dbDatabase.ConnectionString = "Provider=OraOLEDB.Oracle;Data Source=" & strDatabase & ";User ID=" & strUsername & ";Password=" & strPassword & ";"
dbDatabase.Open
'Should verify that the connection attempt was successful, but I will leave that for someone else to code
dbActiveDirectory.Provider = "ADsDSOObject"
dbActiveDirectory.Open "Active Directory Provider"
comData.ActiveConnection = dbActiveDirectory
If Err <> 0 Then
intResult = MsgBox("An error happened while connecting to Active Directory" & vbCrLf & Err.Description, 16, "Oh NO!")
Exit Sub
End If
With comData
strSQL = "SELECT" & vbCrLf
strSQL = strSQL & " NAME" & vbCrLf
strSQL = strSQL & "FROM" & vbCrLf
strSQL = strSQL & " 'LDAP://" & strDomain & "'" & vbCrLf
strSQL = strSQL & "WHERE" & vbCrLf
strSQL = strSQL & " OBJECTCLASS='computer'" & vbCrLf
strSQL = strSQL & "ORDER BY" & vbCrLf
strSQL = strSQL & " NAME"
.CommandText = strSQL
.Properties("Page Size") = 1000
.Properties("Searchscope") = ADS_SCOPE_SUBTREE
End With
Set snpData = comData.Execute
If Err <> 0 Then
intResult = MsgBox("An error happened while reading the computer list from Active Directory" & vbCrLf & Err.Description, 16, "Oh NO!")
Exit Sub
End If
strSQL = "SELECT * FROM Win32_ComputerSystem"
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery(strSQL, "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)
strSQLTable = "CREATE TABLE COMPUTER_LIST (" & vbCrLf
strSQLTable = strSQLTable & " COMPUTER_NAME VARCHAR2(100)," & vbCrLf
strSQLInsert = "INSERT INTO COMPUTER_LIST VALUES (" & vbCrLf
intColumns = 1
With comDataInsert
.Parameters.Append .CreateParameter("computer_name", adVarChar, adParamInput, 100, " ")
For Each objItem In colItems
For Each objProperty In objItem.Properties_
'We are in the header row
intColumns = intColumns + 1
strSQLTable = strSQLTable & " " & Replace(CStr(objProperty.Name), " ", "_") & " VARCHAR2(100)," & vbCrLf
'This method seems to be having problems
'strSQLInsert = strSQLInsert & " ?," & vbCrLf
'.Parameters.Append .CreateParameter("value" & FormatNumber(intColumns, 0), adVarChar, adParamInput, 100, " ")
Next
Next
'This method seems to be having problems
'strSQLInsert = Left(strSQLInsert, Len(strSQLInsert) - 3) & ")"
'.CommandText = strSQLInsert
'.CommandType = adCmdText
'.CommandTimeout = 30
'.ActiveConnection = dbDatabase
End With
strSQLTable = strSQLTable & " PRIMARY KEY (COMPUTER_NAME))"
dbDatabase.Execute strSQLTable
'Alternate method should also use bind variables
strSQLInsert = "SELECT" & vbCrLf
strSQLInsert = strSQLInsert & " *" & vbCrLf
strSQLInsert = strSQLInsert & "FROM" & vbCrLf
strSQLInsert = strSQLInsert & " COMPUTER_LIST" & vbCrLf
strSQLInsert = strSQLInsert & "WHERE" & vbCrLf
strSQLInsert = strSQLInsert & " 1=2"
dynDataInsert.Open strSQLInsert, dbDatabase, adOpenKeyset, adLockOptimistic
strSQL = "SELECT * FROM Win32_ComputerSystem"
dbDatabase.BeginTrans
If snpData.State = 1 Then
Do While Not (snpData.EOF)
If PingTest(CStr(snpData.Fields("Name").Value)) = True Then
Err = 0 'Reset the error indicator
strComputer = CStr(snpData.Fields("Name").Value)
strSpeech = "Checking, " & strComputer
objSpeech.Speak strSpeech
Err = 0
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
If Err = 0 Then
Set colItems = objWMIService.ExecQuery(strSQL, "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)
intColumn = 1
'This method seems to be having problems
'comDataInsert("computer_name") = Left(CStr(strComputer), 100)
dynDataInsert.AddNew
dynDataInsert("computer_name") = Left(CStr(strComputer), 100)
For Each objItem In colItems
intColumn = 1
For Each objProperty In objItem.Properties_
intColumn = intColumn + 1
If Not (IsNull(objProperty.Value)) Then
If VarType(objProperty.Value) <> 8204 Then
'This method seems to be having problems
'comDataInsert("value" & FormatNumber(intColumn, 0)) = Left(objProperty.Value, 100)
dynDataInsert(Replace(CStr(objProperty.Name), " ", "_")) = Left(objProperty.Value, 100)
End If
End If
Next
Next
'This method seems to be having problems
'comDataInsert.Execute
'Alternate method should also use bind variables
dynDataInsert.Update
End If
Else
strComputer = CStr(snpData.Fields("Name").Value)
strSpeech = "Could Not Ping, " & strComputer
objSpeech.Speak strSpeech
End If
snpData.MoveNext
Loop
snpData.Close
strSpeech = "Done!"
objSpeech.Speak strSpeech
Else
If Err <> 0 Then
intResult = MsgBox("An error happened while connecting to Active Directory" & vbCrLf & Err.Description, 16, "Oh NO!")
End If
End If
dbDatabase.CommitTrans
Set objWMIService = Nothing
Set colItems = Nothing
Set objItem = Nothing
Set objProperty = Nothing
Set objSpeech = Nothing
Set dbDatabase = Nothing
Set dynDataInsert = Nothing
Set comDataInsert = Nothing
Set snpData = Nothing
End Sub
Function PingTest(strComputer)
Dim intPosition
Dim objShell
Dim objExec
Dim strLine
Dim strCommand
On Error Resume Next
PingTest = False
Set objShell = CreateObject("wscript.shell")
'command to execute
strCommand = "PING -i 10 -w 10 -n 1 " & strComputer
'Create Exec object
Set objExec = objShell.Exec(strCommand)
'skip lines that contain information about our DNS server
Do While objExec.StdOut.AtEndOfStream <> True
strLine = objExec.StdOut.ReadLine
intPosition = InStr(UCase(strLine), "RECEIVED =")
If intPosition > 0 Then
If InStr(strLine, "TTL expired in transit") = 0 Then
If Trim(Mid(strLine, intPosition + 10, 2)) = "1" Then
PingTest = True
Else
PingTest = False
End If
Else
PingTest = False
End If
Exit Do
End If
Loop
Set objShell = Nothing
Set objExec = Nothing
End Function
Yes, it is that easy… to have the computer talk to you.

Recent Comments