Jump to content

Crashing calling Win32 DBs on certain computers


Recommended Posts

I have a script that pulls information from the different Win32 databases on a machine the user inputs. With certain machines the program will crash while it's trying to access the database. The message I get is that it "Variable must be of type Object". The code for one of the databases where it's crashing is:

$colItems = $objWMIService.ExecQuery("SELECT Caption, FreePhysicalMemory, ServicePackMajorVersion, Version FROM Win32_OperatingSystem", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    
If IsObj($colItems) Then
    For $objItem In $colItems
        $returnArr[0] = $objItem.Caption
        $returnArr[1] = $objItem.FreePhysicalMemory
        $returnArr[2] = $objItem.ServicePackMajorVersion
        $returnArr[3] = $objItem.Version
    Next
Else
    Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_OperatingSystem" )
Endif

It doesn't matter if I put the query inside IsObj(), it still crashes. It doesn't happen with every computer I try. I think there may be a security rights issue behind the problem.

My main concern is, is there a way for it to not crash on errors? I would rather it show an empty value than crash completely.

Link to comment
Share on other sites

- You didn't post a working example

- My guess is, that the WMI service is not started on those machines where your script crashes, so the correct check would be IsObj($objWMIService)

In SMF I use this UDF by Xenobiologist to check whether the service is running and if not trying to start it with this code:

Local $b_WMI_was_running = True
While Not _ServiceRunning("", "winmgmt") ; Check that WMI service is running
    $b_WMI_was_running = False
    Switch MsgBox(4 + 16 + 262144, "SMF - Computer Info Report - Error", "The WMI service is stopped." & @CRLF & "Do you want SMF to try to start it?")
        Case 6
            _StartService("", "winmgmt")
            Sleep(2000)
        Case Else
            Return
    EndSwitch
WEnd

; RUN YOUR WMI CODE HERE

If $b_WMI_was_running = False Then
    While Not _ServiceRunning("", "winmgmt") ; Check that WMI service is running
        Switch MsgBox(4 + 16 + 262144, "SMF - Computer Info Report - Finished", "The WMI service has been started by SMF." & @CRLF & "Do you want SMF to stop the WMI service again?")
            Case 6
                _StopService("", "winmgmt")
                Sleep(2000)
            Case Else
                Return
        EndSwitch
    WEnd
EndIf

- Instead if relying on WMI I recommend to extract the infos you listed above by using this + a call to MemGetStats()

Edit: Upsa, $colItems is an Object, corrected.

Edited by KaFu
Link to comment
Share on other sites

OK, here's the complete re-worked function I have. I only extracted that one part in my first post since I could get the error with only that query. I added the "If IsObj($objWMIService) Then" test starting on line 17 and that worked. So would I need the further IsObj() If Then loops later? It would be nice to take those out, but I can leave them in.

Func _CompInfo($computer)
    $queryPing = Ping($computer)
    
    Dim $returnArr[25]
 
    If $queryPing Then
        $wbemFlagReturnImmediately = 0x10
        $wbemFlagForwardOnly = 0x20
        $colItems = ""
        If $computer <> "" Then
            $strComputer = $computer
        Else
            $strComputer = "localhost"
        EndIf

        $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
        If IsObj($objWMIService) Then
            $colItems = $objWMIService.ExecQuery("SELECT Caption, Domain, Manufacturer, Model, Name, PartOfDomain, Status, SystemType, TotalPhysicalMemory, UserName, Workgroup FROM Win32_ComputerSystem", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
            
            If IsObj($colItems) Then
                For $objItem In $colItems
                    $returnArr[0] = $objItem.Caption
                    $returnArr[1] = $objItem.Domain
                    $returnArr[2] = $objItem.Manufacturer
                    $returnArr[3] = $objItem.Model
                    $returnArr[4] = $objItem.Name
                    $returnArr[5] = $objItem.PartOfDomain
                    $returnArr[6] = $objItem.Status
                    $returnArr[7] = $objItem.SystemType
                    $returnArr[8] = $objItem.TotalPhysicalMemory
                    $returnArr[9] = $objItem.UserName
                    $returnArr[10] = $objItem.Workgroup
                Next
            Else
            Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_ComputerSystem" )
            Endif
        
            $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystemProduct", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
        
            If IsObj($colItems) Then
                For $objItem In $colItems
                    $returnArr[11] = $objItem.Caption
                    $returnArr[12] = $objItem.Description
                    $returnArr[13] = $objItem.IdentifyingNumber
                    $returnArr[14] = $objItem.Name
                    $returnArr[15] = $objItem.SKUNumber
                    $returnArr[16] = $objItem.UUID
                    $returnArr[17] = $objItem.Vendor
                    $returnArr[18] = $objItem.Version
                Next
            Else
            Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_ComputerSystemProduct" )
            Endif
        
            $colItems = $objWMIService.ExecQuery("SELECT Caption, FreePhysicalMemory, ServicePackMajorVersion, Version FROM Win32_OperatingSystem", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
        
            If IsObj($colItems) Then
                For $objItem In $colItems
                    $returnArr[19] = $objItem.Caption
                    $returnArr[20] = $objItem.FreePhysicalMemory
                    $returnArr[21] = $objItem.ServicePackMajorVersion
                    $returnArr[22] = $objItem.Version
                Next
            Else
            Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_OperatingSystem" )
            Endif
        
            $colItems = $objWMIService.ExecQuery("SELECT MaxClockSpeed FROM Win32_Processor", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
        
            If IsObj($colItems) Then
                For $objItem In $colItems
                    $returnArr[23] = $objItem.MaxClockSpeed
                Next
            Else
            Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_Processor" )
            Endif
        Else
            $i = 0
            Do
                $returnArr[$i] = ""
                $i = $i + 1
            Until $i = 25
        EndIf
        
        Return $returnArr
    EndIf
EndFunc   ;==> _CompInfo

On a side note, I realized I was causing a lot of extra work by calling the function for each thing I need to set (i.e. a = func($comp, 1), b = func($comp, 2)). I cleaned it up to just return the whole array and pick what it needs from the returned array. So it speeds things up a little bit.

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...