Jump to content
AndyS19

WMI SQL query results object can only be used once

Recommended Posts

AndyS19

I have code that does a WMI SQL query to find all defined printers, and I want to parse the returned object in several places.  However, after parsing it the first time, all other times fail to find any printer objects.

Here is my test code:

test()

Func test()
    Local $oPrinters, $oPrinter, $err, $cnt, $oP, $query

    $query = "SELECT * FROM Win32_Printer"
    $oPrinters = doQuery($query)

    $err = @error
    LogMsg("+++: $err = " & $err & ", isObj($oPrinters) = " & IsObj($oPrinters))

    If ($err == 0) Then

        LogMsg("FIRST LOOP") ; <=== FIRST LOOP
        $cnt = 0
        $oP = $oPrinters
        LogMsg("+++: isObj($oP) = " & IsObj($oP))

        For $oPrinter In $oP
            $cnt += 1
            LogMsg("+++: isObj($oPrinter): " & IsObj($oPrinter) & ", $oPrinter.Name ==>" & $oPrinter.Name & "<==")
        Next
        LogMsg("+++: Found " & $cnt & " printers")

        LogMsg("SECOND LOOP") ; <== SECOND LOOP
        $cnt = 0
        $oP = $oPrinters
        LogMsg("+++: isObj($oP) = " & IsObj($oP))

        For $oPrinter In $oP
            $cnt += 1
            LogMsg("+++: isObj($oPrinter): " & IsObj($oPrinter) & ", $oPrinter.Name ==>" & $oPrinter.Name & "<==")
        Next
        LogMsg("+++: Found " & $cnt & " printers")
    EndIf

EndFunc   ;==>test

Func doQuery($sQuery, $lnum = @ScriptLineNumber)
    #forceref $lnum
    LogMsg("+++:" & $lnum & ": doQuery(" & '"' & $sQuery & '"' & ") entered")
    Local $oWMIService, $oResults, $errstr
    Local $wbemFlags = BitOR(0x20, 0x10) ; $wbemFlagReturnImmediately and wbemFlagForwardOnly

    $oWMIService = ObjGet("winmgmts:\\" & "localhost" & "\root\CIMV2")

    If (IsObj($oWMIService)) Then

        $oResults = $oWMIService.ExecQuery($sQuery, "WQL", $wbemFlags)

        If (IsObj($oResults)) Then
            LogMsg("+++: doQuery() returns @error = 0, Good: returning the object")
            Return (SetError(0, 0, $oResults)) ;;; Good: return the object
        Else
            $errstr = "" _
                     & "WMI Query failed." & @CRLF _
                     & "This is the query:" & @CRLF _
                     & "   " & $sQuery
            LogMsg("+++: ====>" & $errstr & "<===")
            LogMsg("+++: doQuery() returns @error = 1")
            Return (SetError(1, 0, $errstr)) ; Error: Query faled
        EndIf
    Else
        $errstr = "" _
                 & "WMI Output" & @CRLF _
                 & "No WMI Objects Found for class: " & @CRLF _
                 & "Win32_PrinterDriver" & @CRLF _
                 & "using this query:" & @CRLF _
                 & "   " & $sQuery
        LogMsg("+++: ====>" & $errstr & "<===")
        MsgBox(0, "ERROR", $errstr) ; Error: Cannot get $oWMIService object
        Exit (1)
    EndIf
EndFunc   ;==>doQuery

Func LogMsg($msg, $lnum = @ScriptLineNumber)
    ConsoleWrite("+++:" & $lnum & ": " & $msg & @CRLF)
EndFunc   ;==>LogMsg

Parsing the returned $oPrinters object shows 5 printers:

+++:15: FIRST LOOP
+++:18: +++: isObj($oP) = 1
+++:22: +++: isObj($oPrinter): 1, $oPrinter.Name ==>Microsoft XPS Document Writer<==
+++:22: +++: isObj($oPrinter): 1, $oPrinter.Name ==>Microsoft Office Document Image Writer<==
+++:22: +++: isObj($oPrinter): 1, $oPrinter.Name ==>Fax<==
+++:22: +++: isObj($oPrinter): 1, $oPrinter.Name ==>Canon MG7100 series Printer WS<==
+++:22: +++: isObj($oPrinter): 1, $oPrinter.Name ==>Canon MG6100 series Printer WS<==
+++:24: +++: Found 5 printers

Parsing it again, shows no printers:

+++:26: SECOND LOOP
+++:29: +++: isObj($oP) = 1
+++:35: +++: Found 0 printers

 

Share this post


Link to post
Share on other sites
water

Maybe because the "cursor" is at the end of the resulting record set returned by the query.
You could try to loop throug $oP this way:

For $i = 1 to $oP.count
   ; Process $oP($i)
Next

 


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2018-06-01 - Version 1.4.9.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (2018-01-27 - Version 1.3.3.1) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites
AndyS19

When I try the following, 
$cnt = $oP.count

I get this error:
==> The requested action with this object has failed.:

Share this post


Link to post
Share on other sites
water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2018-06-01 - Version 1.4.9.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (2018-01-27 - Version 1.3.3.1) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites
AndyS19

Right.  When I set the wbem flags to 0 (wait for complete) and went back to my original code, I was able to make multiple passes of the $oPrinters object.  However, no matter what I tried, I could not access one of the printer objects in $oPrinters using an index, like $oPrinters[2].

So it's fixed, thank you,

Share this post


Link to post
Share on other sites
water

:)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2018-06-01 - Version 1.4.9.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (2018-01-27 - Version 1.3.3.1) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
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

  • Similar Content

    • FrancescoDiMuro
      By FrancescoDiMuro
      Good evening everyone
      I'm working on a little project of mines, and I was trying to use WMI Object.
      The question which I don't find an answer is: 
      Once I do the query with WMI Object, something like "SELECT * FROM Win32_LogonSession", instead of specify the field of the collection returned, ( i.e. $colItems.Caption ), can I loop though each property and each value of the property, writing so one row of code only?
      Hope my question was clear enough.
      Thanks in advance.

      Best Regards.
    • dangr82
      By dangr82
       
      I have created this function for a database, but I can not make it work. I always have two error messages: "not an error" ... and the file created, in the script directory, does not contain anything.
      Global $sDBName = "Hen.db" Func DatabaseTable() Local $sConnDB _SQLite_Startup() If @error Then MsgBox($MB_SYSTEMMODAL, "SQLite Error", "SQLite.dll Can't be Loaded!") Exit -1 EndIf $sConnDB = _SQLite_Open($sDBName) If @error Then MsgBox($MB_SYSTEMMODAL, "SQLite Error", "Can't Load Database!") Exit -1 EndIf If Not _SQLite_Exec($sDBName, 'CREATE TABLE Animal ("Name", "Age");') = $SQLITE_OK Then MsgBox($MB_SYSTEMMODAL, "SQLite Error", _SQLite_ErrMsg()) If Not _SQLite_Exec($sDBName, 'INSERT INTO Animale VALUES ("Charlie","5");') = $SQLITE_OK Then MsgBox($MB_SYSTEMMODAL, "SQLite Error", _SQLite_ErrMsg()) _SQLite_Close($sConnDB) _SQLite_Shutdown() EndFunc  
    • ahmet
      By ahmet
      Hello,
      I am trying to make a program that will uninstall some software, provided by some form of a list. I have this
      ; Generated by AutoIt Scriptomatic June 08, 2010 ;#RequireAdmin $sPartialName="java" $wbemFlagReturnImmediately = 0x10 $wbemFlagForwardOnly = 0x20 $colItems = "" $strComputer = "localhost" ;$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2") ;$objWMIService=ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & @ComputerName & "\root\cimv2") $objWMIService=ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & @ComputerName & "\root\cimv2") $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_Product", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly) If IsObj($colItems) then For $objItem In $colItems If StringInStr($objItem.Name,$sPartialName)=1 Then ConsoleWrite("Full name:" & $objItem.Name & @CRLF) RunAs("USERNAME",@ComputerName,"PASSWORD",0,@ComSpec & " /c" & ' wmic product where name="Java 9.0.4 (64-bit)" call uninstall /nointeractive',"C:\WINDOWS\system32\wbem",@SW_MAXIMIZE) ;Run('wmic product where name="Java 9.0.4 (64-bit)" call uninstall /nointeractive',"",@SW_MAXIMIZE) ExitLoop EndIf Next Else Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_Product" ) Endif The script above fails uninstalling software despite providing username and password for admin account. If I run script with admin rights then the software gets uninstalled.
      At the following link there is a script by JLogan3o13 but it does not either uninstall software, unless run as admin..
      Is there some way to uninstall software using wim or wimc by providing user name and password?
       
    • Bilgus
      By Bilgus
      #include <Array.Au3> ;WMI EXAMPLE Local $strComputer = "localhost" Local $sClass = "" Local $objClass Local $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2") ; Display all available Classes in this object _ArrayDisplay(Get_Classes($objWMIService), "AVAILABLE WMI CLASSES", "", 0, Default, "NAME") ;Split string at \n(@LF) place each into an array $sClass = "Win32_BIOS" ;<-The Class I've choosen ;Lets Try out one of the classes Local $objClass = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2:" & $sClass) ConsoleWrite($sClass & @CRLF & "------------------------------------------" & @CRLF) _ArrayDisplay(Split_Properties(Get_Properties($objClass)), $sClass & " Properties", "", 0, Default, "NAME|VALUE") ;No methods available for this one but... ConsoleWrite("Methods:" & @CRLF & @CRLF) Get_Methods($objClass) ;Lets Do it again for the network adapter Class $sProperties = "" $sClass = "Win32_NetworkAdapterConfiguration" ;<-The Class I've choosen ;Lets Try out one of the classes $objClass = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2:" & $sClass) ConsoleWrite($sClass & @CRLF & "------------------------------------------" & @CRLF) _ArrayDisplay(Split_Properties(Get_Properties($objClass)), $sClass & " Properties", "", 0, Default, "NAME|VALUE") ConsoleWrite("Methods:" & @CRLF & @CRLF) Get_Methods($objClass) Func Get_Classes($obj) ; Display all available Classes in this object If IsObj($obj) Then Local $sClasses = "" For $objClass In $obj.SubclassesOf() ;<--WMI Method $sClasses &= ($objClass.Path_.Class) & @LF ;Build a string seperated by \n(@LF) Next EndIf Return StringSplit($sClasses, @LF) EndFunc ;==>Get_Classes Func Get_Methods($objClass) Local $sResults = "" If IsObj($objClass) Then For $objMethods In $objClass.Methods_ ConsoleWrite(@TAB & $objMethods.Name & @CRLF) $sResults &= $objMethods.Name & @LF Next EndIf Return $sResults EndFunc ;==>Get_Methods Func Get_Properties($objClass) Local $sProperties = "" If IsObj($objClass) Then For $objClassProp In $objClass.Properties_() ;<-Another WMI Method For $obj In $objWMIService.ExecQuery("Select * from " & $sClass) ;<-Another WMI Method $sProperties &= $objClassProp.Name & @CR $sProperties &= Parse_Value($obj.Properties_($objClassProp.Name).Value) ;Use the Properties_ Method to call our desired property Next Next EndIf Return $sProperties EndFunc ;==>Get_Properties Func Parse_Value($vValue) Local $sRet = "" Switch StringLower(VarGetType($vValue)) Case "keyword" ; Not really sure what this one is probably NULL $sRet = Number($vValue) = 0 ? "" : Number($vValue) Case "array" $sRet = _ArrayToString($vValue, ", ") Case "string", "bool", "int32", "int64", "double", "binary" $sRet = $vValue Case "pointer" $sRet = "[PTR]:" & $vValue Case Else $sRet = "[" & VarGetType($vValue) & "]: " & $vValue EndSwitch $sRet &= @LF Return $sRet EndFunc ;==>Parse_Value Func Split_Properties($sProperties) Local $aDisp = StringSplit($sProperties, @LF) ;Split string at \n(@LF) place each into an array Local $aTmp If IsArray($aDisp) Then _ArrayColInsert($aDisp, 1) For $i = 1 To $aDisp[0][0] ; String Split stores Count in the first element by default $aTmp = StringSplit($aDisp[$i][0], @CR) ;Split string at \r(@CR) place each into an array If IsArray($aTmp) Then $aDisp[$i][0] = $aTmp[0] > 0 ? $aTmp[1] : "?" ;Check if this element exists if not make it "?" $aDisp[$i][1] = $aTmp[0] > 1 ? $aTmp[2] : " " ;Check if this element exists if not make it " " EndIf Next EndIf Return $aDisp EndFunc ;==>Split_Properties  
    • argumentum
      By argumentum
      ..let's say I store in a mysql column "[1,2,11,12,123]".
      How can I make s query to get all those rows that is 1, or is 12, etc ?
      I'm using  mysqlnd 5.0.11-dev - 20120503 
      Any advise on what technique I should use is welcomed
      Thanks
      PS: ..I'm adding a comma to each end, as in  [,1,2,11,12,123,] and will search with like %,12,% .
      Not pretty but I'm in a hurry and can't come up with a better solution =/
×