-
1
- #1
CherryPanda
MIS
I was looking for a way to speed up data collection via WMI from a large set of servers. After looking at (and rejecting) several different approaches I've decided to try Async queries to poll several hosts simultaneously. Code is below:
Set objSink = WScript.CreateObject("wbemscripting.swbemsink","sink_") 'WBEM Event Sink
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator") 'Common WBEM Locator
Set objQueue = WScript.CreateObject("Scripting.Dictionary") 'Dictionary serves as queue holder
intMaxQueue = 3 'Maximum simultaneous queues
arrComputers = Array("host1","host2","host3","host4","host5","host6") 'Array containing hosts to query
Dim arrAsyncObjects() 'Array containing Async objects
ReDim arrAsyncObjects(intMaxQueue-1, 2) 'Set to match intMaxQueue
For i=0 To intMaxQueue - 1 'Initial array values
Set arrAsyncObjects(i,0) = Nothing
Next
For Each strComputer In arrComputers
For i=0 To intMaxQueue - 1
If TypeName(arrAsyncObjects(i,0)) = "Nothing" Then 'Spot available in the queue
Exit For
End If
Next
objQueue.Add strComputer, i
Set arrAsyncObjects(i,0) = WScript.CreateObject("WbemScripting.SWbemNamedValueSet")
arrAsyncObjects(i,0).Add "AsyncId", strComputer
Set arrAsyncObjects(i,1) = objSWbemLocator.ConnectServer(strComputer, "root\CIMV2")
arrAsyncObjects(i,2) = strComputer
arrAsyncObjects(i,1).ExecQueryAsync objSink, "Select * from Win32_NTLogEvent Where Logfile = 'Application'",,,,arrAsyncObjects(i,0)
While objQueue.Count = intMaxQueue 'If queue is full - sleep until spot is available
WScript.Sleep 1000
Wend
Next
Sub sink_OnObjectReady(objInst, objContext)
WScript.Echo objContext.Item("AsyncId").Value & " - " & objInst.SourceName
End sub
Sub sink_OnCompleted(HResult, objErr, objContext)
WScript.Echo objContext.Item("AsyncId").Value & " - " & "ExecQueryAsync completed"
intIndex = objQueue.Item(objContext.Item("AsyncId").Value) 'Determine which Async objects can be closed
Set arrAsyncObjects(intIndex,0) = Nothing
Set arrAsyncObjects(intIndex,1) = Nothing
arrAsyncObjects(intIndex,2) = ""
objQueue.Remove objContext.Item("AsyncId").Value 'Free up spot in the queue
End Sub
intMaxQueue could be adjusted to suit your needs, arrComputers, WMI "Select .. " statement and sink_OnObjectReady sub should be changed as well. Way I'm using sink_OnObjectReady in my production is by having it fill ADOR recordset, which later on is sorted by computer name.
Overall this helped turn data collection task that was running for over 4 hours into a 20 minutes one.
Set objSink = WScript.CreateObject("wbemscripting.swbemsink","sink_") 'WBEM Event Sink
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator") 'Common WBEM Locator
Set objQueue = WScript.CreateObject("Scripting.Dictionary") 'Dictionary serves as queue holder
intMaxQueue = 3 'Maximum simultaneous queues
arrComputers = Array("host1","host2","host3","host4","host5","host6") 'Array containing hosts to query
Dim arrAsyncObjects() 'Array containing Async objects
ReDim arrAsyncObjects(intMaxQueue-1, 2) 'Set to match intMaxQueue
For i=0 To intMaxQueue - 1 'Initial array values
Set arrAsyncObjects(i,0) = Nothing
Next
For Each strComputer In arrComputers
For i=0 To intMaxQueue - 1
If TypeName(arrAsyncObjects(i,0)) = "Nothing" Then 'Spot available in the queue
Exit For
End If
Next
objQueue.Add strComputer, i
Set arrAsyncObjects(i,0) = WScript.CreateObject("WbemScripting.SWbemNamedValueSet")
arrAsyncObjects(i,0).Add "AsyncId", strComputer
Set arrAsyncObjects(i,1) = objSWbemLocator.ConnectServer(strComputer, "root\CIMV2")
arrAsyncObjects(i,2) = strComputer
arrAsyncObjects(i,1).ExecQueryAsync objSink, "Select * from Win32_NTLogEvent Where Logfile = 'Application'",,,,arrAsyncObjects(i,0)
While objQueue.Count = intMaxQueue 'If queue is full - sleep until spot is available
WScript.Sleep 1000
Wend
Next
Sub sink_OnObjectReady(objInst, objContext)
WScript.Echo objContext.Item("AsyncId").Value & " - " & objInst.SourceName
End sub
Sub sink_OnCompleted(HResult, objErr, objContext)
WScript.Echo objContext.Item("AsyncId").Value & " - " & "ExecQueryAsync completed"
intIndex = objQueue.Item(objContext.Item("AsyncId").Value) 'Determine which Async objects can be closed
Set arrAsyncObjects(intIndex,0) = Nothing
Set arrAsyncObjects(intIndex,1) = Nothing
arrAsyncObjects(intIndex,2) = ""
objQueue.Remove objContext.Item("AsyncId").Value 'Free up spot in the queue
End Sub
intMaxQueue could be adjusted to suit your needs, arrComputers, WMI "Select .. " statement and sink_OnObjectReady sub should be changed as well. Way I'm using sink_OnObjectReady in my production is by having it fill ADOR recordset, which later on is sorted by computer name.
Overall this helped turn data collection task that was running for over 4 hours into a 20 minutes one.