Jump to content

WMI Speed


Recommended Posts

Hey everyone -

I've got a simple script that pulls the name of every computer running Windows XP from AD, and then uses WMI to retrieve the Serial Number of each machine and check it against a specified serial number. The problem is that it runs really slow. There's about 600 computers that it pull, and if it hits one that is offline it takes a few extra seconds and when that's spread over 600 computer it slows it way down (about 30 mins to check all 600 computers). IF you have any ideas on how to speed this up at all, or any improvements I could make it would be appreciated.

Thanks

--LurchMan

Code:

#include <ADfunctions2.au3>

Global $aComputers
$sSN = StringUpper (InputBox ("Serial Number", "Please enter the serial number you are trying to locate:"))
$msg = MsgBox(52, "Warning!", "This program can take up to 30 minuets or more to complete.  Are you sure you wish to continue?")
If $msg = 7 Then Exit
MsgBox (64, "Continuing", "This program will be running in the background with no GUI...")
$sOU = $strDNSDomain
_ADGetObjectsInOU($aComputers,$sOU,"(&(&(&(&(&(objectCategory=Computer)(operatingSystem=Windows XP Professional))))))",2,"name")
_ArraySort ($aComputers)
;~ _ArrayDisplay ($aComputers)
For $i = 1 To UBound($aComputers) - 1
    $colItems = ""
    If Ping ($aComputers[$i], 1000) > 0 Then
        $objWMIService = ObjGet("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _
        & $aComputers[$i] & "\root\cimv2")
        If IsObj ($objWMIService) Then
            $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_SystemEnclosure", "WQL", 0x10 + 0x20)
            If IsObj($colItems) Then
                For $objItem In $colItems
                    If StringUpper($objItem.SerialNumber) = $sSN Then
                        MsgBox (64, "Found It", "Computer Name: " & $aComputers[$i] & " | SN: " & $sSN)
                        Exit
                    EndIf
                Next
            EndIf
        EndIf
    EndIf
Next
MsgBox (64, "Not Found", "Could not find the serial number " & $sSN & " on the network.")

Dating a girl is just like writing software. Everything's going to work just fine in the testing lab (dating), but as soon as you have contract with a customer (marriage), then your program (life) is going to be facing new situations you never expected. You'll be forced to patch the code (admit you're wrong) and then the code (wife) will just end up all bloated and unmaintainable in the end.

Link to comment
Share on other sites

The biggest bottlenecks are going to be the Ping and the WMI Connection, which I'm not sure what you can do about that. You could make the query (potentially but unrealistically) more defined, and just a side note...Win32_SystemEnclosure may not always have the SerialNumber property. Try Win32_BIOS instead.

untested:

$colItems = $objWMIService.ExecQuery("SELECT SerialNumber FROM Win32_BIOS", "WQL", 0x10 + 0x20)
Link to comment
Share on other sites

$colItems = $objWMIService.ExecQuery("SELECT SerialNumber FROM Win32_BIOS", "WQL", 0x10 + 0x20)

With this would i still just use $objitem.serialnumber to get the data?

Edit: Nevermind...forgot to think and test before posting...I'll give that a try and see if its any better.

Edited by LurchMan

Dating a girl is just like writing software. Everything's going to work just fine in the testing lab (dating), but as soon as you have contract with a customer (marriage), then your program (life) is going to be facing new situations you never expected. You'll be forced to patch the code (admit you're wrong) and then the code (wife) will just end up all bloated and unmaintainable in the end.

Link to comment
Share on other sites

Hi,

it is maybe faster. My idea is, to check the computers by a Dos ping with several pings at the 'same time' and then check the ping visible computers by wmi.

1) Compile your own 'ping'.exe. I compiled it as _myping.exe in @ScriptDir as console application

!! See @Edit at the end !!

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Change2CUI=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <Constants.au3>
;1 ping to computer, which is param 1 on commandline
$pid = Run(@ComSpec & " /c ping -n 1 " & $CmdLine[1], @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
Local $line
While 1
    $line = StdoutRead($pid)
    If @error Then ExitLoop
    ;get reply -> write computername into result file
    If StringInStr ($line, "Reply from") Then 
        FileWriteLine (@ScriptDir & "\_myping.txt", $CmdLine [1])
    EndIf
Wend

2) Changes to your script:

#include <Constants.au3>
#include <ADfunctions2.au3>
#Include <File.au3>

Global $aComputers
; amount of hidden cmd boxes running
Global $proccount = 30
;delete existing resultfile from _myping.exe
If FileExists (@ScriptDir & "\_myping.txt") Then FileDelete (@ScriptDir & "\_myping.txt")

Global $sSN = StringUpper (InputBox ("Serial Number", "Please enter the serial number you are trying to locate:"))
$msg = MsgBox(52, "Warning!", "This program can take up to 30 minuets or more to complete.  Are you sure you wish to continue?")
If $msg = 7 Then Exit
MsgBox (64, "Continuing", "This program will be running in the background with no GUI...")
$sOU = $strDNSDomain
_ADGetObjectsInOU($aComputers,$sOU,"(&(&(&(&(&(objectCategory=Computer)(operatingSystem=Windows XP Professional))))))",2,"name")
_ArraySort ($aComputers)
;~ _ArrayDisplay ($aComputers)
For $i = 1 To UBound($aComputers) - 1
    ;get amount of _myping processes
    $arproc = ProcessList ("_myping.exe")
    ;If defined proccount is reached, wait until amount of processes is smaller then proccount
    If $arproc [0] [0] = $proccount Then
        Do
            sleep (1000)
            $arproc = ProcessList ("_myping.exe")
        Until $arproc [0] [0] < $proccount
    EndIf
    ;Pinging several computers at nearly the 'same time'
    Run ("_myping.exe " & $aComputers [$i], @ScriptDir, @SW_HIDE)
Next

;wait until all _myping processes are finished
Do
    sleep (100)
    $arproc = ProcessList ("_myping.exe")
Until $arproc [0] [0] = 0

;read result file into array
_FileReadToArray (@ScriptDir & "\_myping.txt", $result)
;loop over result array and start wmi
For $i = 1 To $result [0]
    _wmiserial ($result [$i])
Next

Func _wmiserial ($computer)
    $objWMIService = ObjGet("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" _
    & $computer & "\root\cimv2")
    If IsObj ($objWMIService) Then
        $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Bios", "WQL", 0x10 + 0x20)
        If IsObj($colItems) Then
            For $objItem In $colItems
                If StringUpper($objItem.SerialNumber) = $sSN Then
                    MsgBox (64, "Found It", "Computer Name: " & $computer & " | SN: " & $sSN)
                    Exit
                EndIf
            Next
        EndIf
    EndIf
    ;MsgBox (64, "Not Found", "Could not find the serial number " & $sSN & " on the network.")
EndFunc

I cant test it by myself, because at home i have only single PC without AD. Maybe you can give it a try.

;-))

Stefan

@Edit: Faster _myping.exe Version:

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Change2CUI=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
AutoItSetOption ("TCPTimeout", 250)
$var = Ping ($CmdLine[1], 250)
If $var Then FileWriteLine (@ScriptDir & "\_myping.txt", $CmdLine [1])
Edited by 99ojo
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...