Me Myself
Me Myself

Reputation: 129

VBScript WMI Class and Property Exist

My company is trying to find what machines were not loaded with our images. We added in WMI a class called Revision_Detail, but due to inconsistencies, it was not populated on all versions of our images.

I put together the below to check if the Revision_Detail exists, then check if it is not null. If it is null it reverts to ImageRevision class, which everyone of our images has.

My problem is the function I came across (and are using), cycles through all of CIMV2 classes and is a bit slow.

Is there a way to just execute the query and catch the error that Revision Detail doesn't exists?

Function WMIClassExists(strComputer, WMIClassName)
    WMIClassExists = vbFalse 
    Dim objWMIService: Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") 
    Dim colClasses: Set colClasses = objWMIService.SubclassesOf() 
    Dim objClass 
    For Each objClass In colClasses 
        if instr(objClass.Path_.Path,WMIClassName) Then 
            WMIClassExists = vbTrue 
        End if 
    Next 
    Set objWMIService = Nothing 
    Set colClasses = Nothing 
End Function

Set wshNetwork = WScript.CreateObject("WScript.Network") 

strComputer = wshNetwork.ComputerName 

If WMIClassExists(strComputer,"Revision_Detail") Then
    'Found Revision_Detail
    WSCript.Echo strWMIClass & " WMI class does exists on " & strComputer 
    Set Wmi = GetObject("winmgmts:\\" & strComputer & "\ROOT\CIMV2") 
    SET colItems = Wmi.ExecQuery("SELECT * FROM Revision_Detail")

    For Each objItem in colItems
        if IsNull(objItem.CurrentBuild) Then
            'If CurrentBuild doesnt exist, check ImageRevision
            SET colItems2 = Wmi.ExecQuery("SELECT * FROM ImageRevision")

            For Each objItem2 in colItems2 
                wscript.echo "ImageRevision: " & objItem2.ImageRevision
            Next            
        else
            'Revision_Detail exists and is not blank
            wscript.echo "CurrentBuild: " & objItem.CurrentBuild
            wscript.echo "StartBuild: " & objItem.StartBuild
        end if
    Next

Else 
    'Must not be an our image
    WSCript.Echo strWMIClass & " WMI class does not exists on " & strComputer 
End if

Upvotes: 1

Views: 1586

Answers (2)

user6432984
user6432984

Reputation:

I'm sure that it can be done but you'll have to wait for objWMIService to timeout every time it's ping a device that is down. Conversely you can take a call me when your ready approach. Create a script that check for the image on the local machine and saves it's findings to a file on the sever. You can then have Group Policy schedule a task on all the machines to run new script locally.

Updated: I tightened up your code a bit to reducing the overall complexity.

On Error Resume Next

And

On Error GoTo 0

Needed to be move inside the for each loop. Since On Error GoTo 0 was outside the loop the Err object couldn't be reset to 0 until the for each loop exited.

Function GetWmiObjects(wmi, wql)
    Dim items, item, i, result
    Set items = wmi.ExecQuery(wql)

    For Each item In items
        On Error Resume Next
        If Err.Number = 0 Then
            i = UBound(result) + 1
            ReDim Preserve result(i)
            Set result(i) = item
        End If
        On Error GoTo 0
    Next

    GetWmiObjects = result
End Function

Upvotes: 0

Tomalak
Tomalak

Reputation: 338316

Is there a way to just execute the query and catch the error that Revision Detail doesn't exists?

Sure that's possible. Catching errors in VBScript is done with On Error Resume Next (docs).

Since the WMI object collections are a bit awkward to work with, I have created a helper function that executes a WMI query and returns an array instead of a collection:

Function GetWmiObjects(wmi, wql)
    Dim items, item, i, result
    Set items = wmi.ExecQuery(wql)

    ' count items 
    On Error Resume Next
    i = 0
    For Each item In items
        If Err.Number = 0 Then i = i + 1
    Next
    On Error GoTo 0

    ' allocate array of the proper size
    ReDim result(i - 1)

    ' transfer items to array
    If i > 0 Then
        i = 0
        For Each item In items
            Set result(i) = item
            i = i + 1
        Next
    End If

    GetWmiObjects = result
End Function

Now it's easy to do:

Set wmi = GetObject("winmgmts:\\.\ROOT\CIMV2")

Revision_Detail = GetWmiObjects(wmi, "SELECT * FROM Revision_Detail")

If Count(Revision_Detail) = 0 Then
    Wscript.Echo "Revision_Detail not found"
Else
    Wscript.Echo Revision_Detail(0).CurrentBuild
End If

where Count is a convenience function that returns the size of an array:

Function Count(array)
    Count = UBound(array) + 1
End Function

Upvotes: 1

Related Questions