Irios

How to enumerate all properties in an object variable (wmi) when I don't know their names? [SOLVED!]

15 posts in this topic

#1 ·  Posted (edited)

First post here, please be gentle ;)

 

I've spent hours and hours trying to figure out this puzzle. It's impossible to google for because I don't know the precise terminology to use. All msdn links I find are either dead or has been removed like 10 years ago.

 

Here is a tiny code example:

$objWMIService = ObjGet("winmgmts:")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_Tcpip_NetworkInterface Where Name like '%intel%'")
For $objItem In $colItems
    ConsoleWrite($objItem.PacketsPersec & @CRLF)
Next

In that example I'm using the asterix * and it retrieves all properties in the "Win32_PerfRawData_Tcpip_NetworkInterface" class.  But I'm only utilizing "PacketsPersec" in the example.

How could I enumerate all the properties without defining their names beforehand?

(FYI, I do know their names, but the script doesn't know the names)

In other words; how can I use "SELECT *" on any class and output all properties, one by one? Without having to manually specify each property with $objItem.<propertyname> ?


As comparison, using wmic in a cmd shell ...

    wmic path Win32_PerfRawData_Tcpip_NetworkInterface  Where "Name like '%intel%'" get /value

...and it lists all properties in "Names=Value" manner.

This is sort of the same function I'm looking for. How could I do the same in Autoit?

 

 

EDIT: I cannot run a powershell or cmd  to "solve" the problem.  I need to find a way to do this "internally" in Autoit. I.e. by calling the WMI service directly with ObjGet(winmgmts:) or connect to the WMI system with CreateObject("WbemScripting.SWbemLocator"). Performance is a major factor.

Edited by Irios
Solved! :D
1 person likes this

Share this post


Link to post
Share on other sites



Local $strComputer = "."
Local $strNameSpace = "root\cimv2"
Local $strClass = "Win32_PerfRawData_Tcpip_NetworkInterface"

Local $objClass = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\" & $strNameSpace & ":" & $strClass)
For $objClassProperty In $objClass.Properties_
    ConsoleWrite($objClassProperty.Name & @CRLF)
Next

 


Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Share this post


Link to post
Share on other sites

Hi there, Terenz.

I must admit I already had a look into ".Properties_" earlier on, but I don't understand its inner workings, tbh. Or rather, I don't know how to get BOTH the property names AND values... in one go.

In your script example... if you output "$objClass.Value" as well, it is just empty. (I'm guessing it's not really the Value for the property at all)

; ../..
ConsoleWrite($objClassProperty.Value & @CRLF)
; ../..

 

Is it a different object "type" altogether? This is my problem, I'm having a hard time getting a grasp on these objects (where do I start to read about this?), and how are they structured internally? (Do you have any simple examples to illustrate this? Or an info page link?)

I could use your script example combined with my own script to get both property names and their respective values, but it's not very efficient and you're then doing two wmi calls. There must be a way to do this in a single run.

Share this post


Link to post
Share on other sites

Hi @Irios perhaps you can try WMI Explorer. Its a tool for displaying WMI Namespaces, Classes and Properties. WMI Explorer
A Way to get both the property and value written to the console is in the example below.

Local $objWMIService = ObjGet("winmgmts:\\" & "." & "\root\CIMV2")
Local $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_PerfRawData_Tcpip_TCP")

If IsObj($colItems) then
   For $objItem In $colItems
      ConsoleWrite ("Caption: " & $objItem.Caption & @CRLF )
      ConsoleWrite ("ConnectionFailures: " & $objItem.ConnectionFailures & @CRLF )
      ConsoleWrite ("ConnectionsActive: " & $objItem.ConnectionsActive & @CRLF )
      ConsoleWrite ("ConnectionsEstablished: " & $objItem.ConnectionsEstablished & @CRLF )
      ConsoleWrite ("ConnectionsPassive: " & $objItem.ConnectionsPassive & @CRLF )
      ConsoleWrite ("ConnectionsReset: " & $objItem.ConnectionsReset & @CRLF )
      ConsoleWrite ("Description: " & $objItem.Description & @CRLF )
      ConsoleWrite ("Frequency_Object: " & $objItem.Frequency_Object & @CRLF )
      ConsoleWrite ("Frequency_PerfTime: " & $objItem.Frequency_PerfTime & @CRLF )
      ConsoleWrite ("Frequency_Sys100NS: " & $objItem.Frequency_Sys100NS & @CRLF )
      ConsoleWrite ("Name: " & $objItem.Name & @CRLF )
      ConsoleWrite ("SegmentsPersec: " & $objItem.SegmentsPersec & @CRLF )
      ConsoleWrite ("SegmentsReceivedPersec: " & $objItem.SegmentsReceivedPersec & @CRLF )
      ConsoleWrite ("SegmentsRetransmittedPersec: " & $objItem.SegmentsRetransmittedPersec & @CRLF )
      ConsoleWrite ("SegmentsSentPersec: " & $objItem.SegmentsSentPersec & @CRLF )
      ConsoleWrite ("Timestamp_Object: " & $objItem.Timestamp_Object & @CRLF )
      ConsoleWrite ("Timestamp_PerfTime: " & $objItem.Timestamp_PerfTime & @CRLF )
      ConsoleWrite ("Timestamp_Sys100NS: " & $objItem.Timestamp_Sys100NS & @CRLF )
   Next
Else
    Msgbox (48, "WMI Error", "WMI Error")
Endif

 

1 person likes this

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Hi pluto41,

Like I wrote in my initial post, I need a way to do it without having to define all the property names beforehand in the code. (Your example will only output properties you specifically define in the code). I want to gather all properties (SELECT *), no matter the name, and then output the Name and its respective Value.

 

EDIT: You refer to WMI Explorer 2... if you use the PowerShell output there... See how it's done with PS? The script actually parses the WMI data and displays it as "Property : Value"... without having to define each Property first. That's  what I'm looking for in AutoIt.

 

WMI Explorer 2 Powershell example:

$computer = $env:COMPUTERNAME
$namespace = "ROOT\CIMV2"
$classname = "Win32_PerfRawData_Tcpip_NetworkInterface"

 

Get-WmiObject -Class $classname -ComputerName $computer -Namespace $namespace |

    Select-Object * -ExcludeProperty PSComputerName, Scope, Path, Options, ClassPath, Properties, SystemProperties, Qualifiers, Site, Container |
    Format-List -Property [a-z]*

 

 

 

 

WMI Explorer 2 Powershell example output:

BytesReceivedPersec             : 105906295
BytesSentPersec                 : 1472390918
BytesTotalPersec                : 1578297213
Caption                         :
CurrentBandwidth                : 1000000000
Description                     :
Frequency_Object                : 0
Frequency_PerfTime              : 3521210
Frequency_Sys100NS              : 10000000
Name                            : Intel[R] 82579V Gigabit Network Connection
OffloadedConnections            : 0
OutputQueueLength               : 0
PacketsOutboundDiscarded        : 0
PacketsOutboundErrors           : 0
PacketsPersec                   : 1440415
PacketsReceivedDiscarded        : 0
PacketsReceivedErrors           : 0
PacketsReceivedNonUnicastPersec : 23105
PacketsReceivedPersec           : 313482
PacketsReceivedUnicastPersec    : 290377
PacketsReceivedUnknown          : 0
PacketsSentNonUnicastPersec     : 3858
PacketsSentPersec               : 1126933
PacketsSentUnicastPersec        : 1123075
Timestamp_Object                : 0
Timestamp_PerfTime              : 13100603957
Timestamp_Sys100NS              : 131179061249680000

Edited by Irios

Share this post


Link to post
Share on other sites

@Irios if you're looking for both the property name and the value in a single pass I would do something like this:

Local $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Local $oItems = $oWMI.ExecQuery("Select * FROM Win32_PerfRawData_Tcpip_NetworkInterface")
    For $sItem In $oItems
        For $sProperty In $sItem.Properties_
            ConsoleWrite($sProperty.Name & ": " & $sProperty.Value & @CRLF)

        Next
    Next

 Just be aware that some properties may return an array rather than a string. So you might have to code a For loop to gather all the values.

1 person likes this

√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites

Oke @Irios I understand what you mean. Very interesting problem. I spend a hour or so to play a bit with the concept but i can't get it to work :( Anyway this is my try.

Local $strComputer = "."
Local $strNameSpace = "root\cimv2"
Local $strClass = "Win32_PerfRawData_Tcpip_NetworkInterface"
Local $objClass = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\" & $strNameSpace & ":" & $strClass)

Local $objWMIService = ObjGet("winmgmts:\\" & "." & "\root\CIMV2")

Local $colItems
For $objProperty In $objClass.Properties_
    ConsoleWrite ( "=========> " & $objProperty.Name & " " )
    $colItems = $objWMIService.ExecQuery("SELECT " & $objProperty.Name & " FROM Win32_PerfRawData_Tcpip_TCP")
    For $objItem in $colItems
        ; Oke does not work but we are in the loop so something is going on here.
        Local $sValue = Execute ($objItem.Name)     ; attempt to retrieve the contents of $objItem.Name rather then the object.property itself.
        ConsoleWrite ( "Value : " & $sValue & @CRLF )
    Next
Next

 

Share this post


Link to post
Share on other sites

@pluto41 you've already made the call to the class, no need to do it again.


√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites
28 minutes ago, JLogan3o13 said:

@Irios if you're looking for both the property name and the value in a single pass I would do something like this:

../..

Super thanks, @JLogan3o13

That was exactly what I was looking for!

 

 

 

Share this post


Link to post
Share on other sites

Glad to be of assistance :)

1 person likes this

√-1 2^3 ∑ π, and it was delicious!

Share this post


Link to post
Share on other sites

@JLogan3o13 Yup good job! This was exactly where i was after but now i see you use ExecQuery and i used the code posted earlier in the topic.

Local $strComputer = "."
Local $strNameSpace = "root\cimv2"
Local $strClass = "Win32_PerfRawData_Tcpip_NetworkInterface"

Local $objClass = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\" & $strNameSpace & ":" & $strClass)
For $objClassProperty In $objClass.Properties_
    ConsoleWrite($objClassProperty.Name & @CRLF)
    ConsoleWrite($objClassProperty.Value & @CRLF)   ; does not work!!!
Next

In this case there isn't a .Value so i tried to program around it. Which wasn't a succes :P Thanks for sharing your'e code. Excellent! (y)

Share this post


Link to post
Share on other sites

So, now that I have a solution, I still don't understand how to know where to use ".Properties_" and what I might expect find inside it. I do know in regard of WMI Classes and their Properties, of course. That's what this example was about.

Is there some kind of reference where i can learn about this? You have no idea the amount of time I've spent on this little problem now, and I'm not really getting anywhere. Just copying in a solution given by someone else doesn't really provide the basis for expanding and exploring these objects further.

I've had a look at OleView.Exe, but that doesn't help me at all. Just as stuck. I can't even find any wmi classes or namespaces in there :/

 

Share this post


Link to post
Share on other sites

@pluto41

I've more or less already tried those approaches you suggested, in one way or another. And, yeah you can sort of make it do the job, but not in a very efficient way. I really wanted a way do it "in one go". After all, PS and WMIC could do it. I knew it was possible, I just couldn't figure it out myself.

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Yeah, the basics of WMI (retrieving data) isn't something I'm struggling with, to be honest. I've been using WMIC and WQL for quite a while, so I know those things pretty good now.

But using objects to retrieve data from WMI is brand new to me. COM, WBEM, etc. I really don't know where to start. It's quite overwhelming, and I figured if I'd just get a few starters by googling some practical examples, I might figure it out by myself. But no, haha. Like you say, I've obviously got a lot of reading ahead of me :D

Edited by Irios
letters and words

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

    • ModemJunki
      By ModemJunki
      Edit: I found out from looking into the post from coffeeturtle that not all motherboards support WMI temperature reading. You have to explore the WMI namespaces for your system!
      I (stupidly) fried a computer. It was an old Zotac small form factor device that was junked at work, so I turned it into a home theater PC.
      But I had put it in my "audio rack", which has glass doors and not very good ventilation. Normally I would open the doors while it was running and I use a media remote which would hibernate the system. At some point, it woke up by itself (probably Windows Update) and did not go to sleep again. Unfortunately this happened during the summer months while I was away on a small holiday and of course the glass doors were closed.
      When I finally noticed the system was on, it was super hot and the fan was at full blast. Dead. No POST, no green light on the mainboard even with a new power supply, old mechanical laptop hard drive gives errors when connected to another device. My next home project will be to make some appropriate ventilation in the audio cabinet.
      For the replacement I bought a used HP ultra small form factor machine and decided to start working on an app to monitor the ambient temperature sensor on the motherboard and shutdown the system if needed. I used some code for smooth label updates from here (needed updating to work with latest AutoIT) and temperature conversion from here (not really needed, only if you want temperatures in something other than C).
      Maybe I will work on this some more and make it configurable with an .INI file or even storing the settings in registry, but since I probably won't I thought I'd put it up as an example of what a non-expert can do with an afternoon of coding and ideas from the community here.
      This uses an ambient temperature sensor populated on HP machines in HP-specific WMI extensions but the WMI query can easily be changed to any available sensor including CPU or GPU.
      The watchdog monitors temperature, warns with S.O.S beeping if the set point is exceeded, and either shuts down if a timeout is reached while the temperatures are high or goes back to monitoring if the temperature goes lower then the set point, and logs events to the Windows application event logs.
      The GUI it puts up is very small at the top center of the screen (very small on a 4k display anyway).
      #requireadmin because of the WMI query.
      A timer for the WMI query because of prior experience using similar functions in WinPE to get model infos from HP WMI bios extensions.
      If you play around with this, please post your fixes/improvements/changes back to this thread.
      Have fun!
      Edit: Updated to show "Unable to query temperature" if the WMI query returns a null
      #AutoIt3Wrapper_Icon=temperature-2-multi-size.ico #RequireAdmin #NoTrayIcon #include <Temperature.au3> #include <FFLabels.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Global $winLogger = "C:\WINDOWS\system32\eventcreate.exe" ; application to use for event logging Global $MessageSource = "HP TempMon" Global $width = 185 Global $height = 15 Global $FontSize = 8 Global $FontFamily = 'Microsoft Sans Serif' Global $normClr = 0xFF000000 Global $warnClr = 0xFF0000 Global $WMInameSpace = "HP_BIOSNumericSensor" ;~ Global $WMIReadSensor = "Chassis Thermal Index" ; HP 8300 Global $WMIReadSensor = "System Ambient Temperature" ; HP Z400 Global $warnTmp = 46.1111111111 ; degrees C ;~ Global $warnTmp = 24 ; degrees C for testing Global $ovrtmpTime = 5 ; in minutes Global $hGUI = GUICreate("Board Temperature", $width, $height, -1, 0, BitOR($WS_SYSMENU, $WS_POPUP), BitOR($WS_EX_TOPMOST, $WS_EX_WINDOWEDGE, $WS_EX_TOOLWINDOW)) Global $lb1 = _GUICtrlFFLabel_Create($hGUI, "", -1, -1, $width, $height, 8, -1, 0, 1, $normClr) GUISetState(@SW_SHOW) _TempSenseLoop() Func _TempSenseLoop() While 1 Sleep(250) $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE GUIDelete($hGUI) Return Case Else $s_ambTempC = _doQueryHPNumSens(5, $WMInameSpace, $WMIReadSensor, "100") ; + 100 Select Case $s_ambTempC = "" _GUICtrlFFLabel_SetTextColor($lb1, $normClr) _GUICtrlFFLabel_SetData($lb1, "Unable to query temperature") Case $s_ambTempC < $warnTmp _GUICtrlFFLabel_SetTextColor($lb1, $normClr) _GUICtrlFFLabel_SetData($lb1, "Board temperature: " & $s_ambTempC & "C" & "/" & Round(_CelsiusToFahrenheit($s_ambTempC), 0) & "F") Case Else _GUICtrlFFLabel_SetTextColor($lb1, $warnClr) _GUICtrlFFLabel_SetData($lb1, "Board temperature: " & $s_ambTempC & "C" & "/" & Round(_CelsiusToFahrenheit($s_ambTempC), 0) & "F") _doLog("System ambient temperature has exceeded " & $warnTmp & "C.", "WARN", $MessageSource) _AlarmMonitor($ovrtmpTime, $warnTmp) EndSelect EndSwitch WEnd EndFunc ;==>_TempSenseLoop Func _AlarmMonitor($min, $tmp) Local $Shutdown = 1 Local $s_ambTemp Local $freq = 3500 Local $shrt = 200 Local $long = 500 Local $timer = TimerInit() Local $wait = 1000 * ($min * 60) While TimerDiff($timer) < $wait $s_ambTemp = _doQueryHPNumSens(5, $WMInameSpace, $WMIReadSensor, "100") ; + 100 If $s_ambTemp >= $tmp Then _GUICtrlFFLabel_SetData($lb1, "WARNING! OVERTEMP!") Beep($freq, $shrt) Beep($freq, $shrt) Beep($freq, $shrt) Sleep(250) Beep($freq, $long) Beep($freq, $long) Beep($freq, $long) Sleep(250) Beep($freq, $shrt) Beep($freq, $shrt) Beep($freq, $shrt) _GUICtrlFFLabel_SetData($lb1, "Board temperature: " & $s_ambTemp & "C" & "/" & _CelsiusToFahrenheit($s_ambTemp) & "F") Sleep(2000) ElseIf $s_ambTemp < $tmp Then $Shutdown = 0 ExitLoop EndIf WEnd If $Shutdown = 1 Then _doLog("The system is shutting down due to overtemperature conditions. The temperature at the time of shutdown was " & $s_ambTemp & "C" & "/" & _CelsiusToFahrenheit($s_ambTemp) & "F", "ERRR", $MessageSource) Shutdown(24) ElseIf $Shutdown = 0 Then _doLog("System ambient temperature has been reduced below " & $warnTmp & "C.", "INFO", $MessageSource) EndIf EndFunc ;==>_AlarmMonitor Func _doQueryHPNumSens($min, $class, $name, $sleep) ; $sleep = milliseconds Local $s_tempReading = "" Local $s_HPBiosWMIService = "winmgmts:\\" & @ComputerName & "\Root\HP\InstrumentedBIOS" Local $objHPBiosWMIService = ObjGet($s_HPBiosWMIService) Local $s_biosQuery = $objHPBiosWMIService.ExecQuery("select * from " & $class & " where Name='" & $name & "'") $timer = TimerInit() ; we may need to wait for the HP WMI extensions to enumerate in WMI, in WinPE this takes some minutes. $wait = 1000 * ($min * 60) If Not IsObj($s_biosQuery) Then ; we do need to wait, put up a splash screen $s_WMISplash = 1 SplashTextOn("WMI", "Probing WMI (up to 10 minutes)...", 300, 50, -1, -1, 1) Sleep(1000) While TimerDiff($timer) < $wait Sleep(500) $objHPBiosWMIService = ObjGet($s_HPBiosWMIService) If IsObj($objHPBiosWMIService) Then Sleep(500) $colProdName = $s_biosQuery If IsObj($colProdName) Then For $oItem In $colProdName $s_tempReading = $oItem.CurrentReading Next EndIf EndIf WEnd ElseIf IsObj($s_biosQuery) Then ConsoleWrite($s_biosQuery & @CRLF) For $oItem In $s_biosQuery $s_tempReading = $oItem.CurrentReading Next Else $s_tempReading = 0 EndIf Sleep($sleep) Return $s_tempReading EndFunc ;==>_doQueryHPNumSens Func _doLog($message, $type, $msgsrc) Select Case $type = "INFO" $logTyp = "INFORMATION" Case $type = "WARN" $logTyp = "WARNING" Case $type = "ERRR" $logTyp = "ERROR" EndSelect If FileExists($winLogger) Then RunWait(@ComSpec & " /c " & $winLogger & " /L Application /T " & $logTyp & " /SO " & Chr(34) & $msgsrc & Chr(34) & " /ID 1000 /D " & Chr(34) & $message & Chr(34), "", @SW_HIDE) EndIf EndFunc ;==>_doLog  
       
       
      Temperature.au3
      FFLabels.au3
      HP_Temp.au3
    • ModemJunki
      By ModemJunki
      Hello,
      In Windows 10 PowerShell, one can do this to change the metric for a NIC in Windows 10:
      Get-NetAdapter | Where-Object -FilterScript {$_.InterfaceAlias -Eq "Ethernet 2"} | Set-NetIPInterface -InterfaceMetric 2 I know I can script the above PowerShell line (and it works!), but I wanted to try something I hadn't done before after looking into jguinch's most excellent Network configuration UDF. I wanted to make use of the SetIPConnectionMetric method in the WMI classes. There is an example VBscript here but this is not for Windows 10. Using AutoIT would also give better control over capturing error return codes than with PowerShell.
      But I cannot get my script to work! The return from SetIPConnectionMetric() is 0, which would indicate success. Yet the change does not happen. I also tried WMI methods using .put_ but this fails.
      Anyone more experienced than I have ideas to make this work?
      #RequireAdmin _SetNicInterfaceMetric2("Ethernet 2", "2") Func _SetNicInterfaceMetric2($NIC_NAME, $METRIC) Local $s_setIndx = 0 $objWMIService = ObjGet("winmgmts:{impersonationLevel = impersonate}!\\" & "." & "\root\cimv2") $colNICItems = $objWMIService.ExecQuery("SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID = '" & $NIC_NAME & "'", "WQL") If IsObj($colNICItems) Then For $objItem In $colNICItems $s_nicIndex = $objItem.Index Next ConsoleWrite("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = '" & $s_nicIndex & "'" & @CRLF) $colNAC = $objWMIService.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = '" & $s_nicIndex & "'", "WQL") If IsObj($colNAC) Then For $objNetCard In $colNAC If $METRIC <> $objNetCard.IPConnectionMetric Then ConsoleWrite("Metric was set to " & $objNetCard.IPConnectionMetric & ". Setting to " & $METRIC & "." & @CRLF) $s_isSet = $objNetCard.SetIPConnectionMetric($METRIC) ConsoleWrite("SetIPConnectionMetric Result = " & $s_isSet & @CRLF) Else ConsoleWrite("Metric is already set to " & $METRIC & @CRLF) EndIf Next EndIf EndIf EndFunc ;==>_SetNicInterfaceMetric2  
    • AndyS19
      By 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  
    • jguinch
      By jguinch
      Hello.
      I did create these few functions several months ago. I post here, if it can interest someone.
      These functions based on WMI queries allow you to manage printers : add / delete printer, driver, port, or obtain configuration, set default printer ... I let you discover it with the code.

       
      Here is the list of the available functions :
      _Printmgr_AddLocalPort
      _Printmgr_AddLPRPort
      _PrintMgr_AddPrinter
      _PrintMgr_AddPrinterDriver
      _PrintMgr_AddTCPIPPrinterPort
      _PrintMgr_AddWindowsPrinterConnection
      _PrintMgr_CancelAllJobs
      _Printmgr_EnumPorts
      _PrintMgr_EnumPrinter
      _PrintMgr_EnumPrinterConfiguration
      _PrintMgr_EnumPrinterDriver
      _PrintMgr_EnumPrinterProperties
      _PrintMgr_EnumTCPIPPrinterPort
      _Printmgr_Pause
      _Printmgr_PortExists
      _Printmgr_PrinterExists
      _Printmgr_PrinterSetComment
      _Printmgr_PrinterSetDriver
      _Printmgr_PrinterSetPort
      _Printmgr_PrinterShare
      _Printmgr_PrintTestPage
      _PrintMgr_RemoveLocalPort
      _PrintMgr_RemoveLPRPort
      _PrintMgr_RemovePrinter
      _PrintMgr_RemovePrinterDriver
      _PrintMgr_RemoveTCPIPPrinterPort
      _PrintMgr_RenamePrinter
      _Printmgr_Resume
      _PrintMgr_SetDefaultPrinter
       
      And some examples :
      #Include "PrintMgr.au3" ; Remove a printer called "My old Lexmark printer" : _PrintMgr_RemovePrinter("My old Lexmark printer") ; Remove the driver called "Lexmark T640" : _PrintMgr_RemovePrinterDriver("Lexmark T640") ; Remove the TCP/IP printer port called "TCP/IP" _PrintMgr_RemoveTCPIPPrinterPort("MyOLDPrinterPort") ; Add a driver, called "Samsung ML-451x 501x Series", and driver inf file is ".\Samsung5010\sse2m.inf" _PrintMgr_AddPrinterDriver("Samsung ML-451x 501x Series", "Windows NT x86", @scriptDir & "\Samsung5010", @scriptDir & "\Samsung5010\sse2m.inf") ; Add a TCP/IP printer port, called "MyTCPIPPrinterPort", with IPAddress = 192.168.1.10 and Port = 9100 _PrintMgr_AddTCPIPPrinterPort("MyTCPIPPrinterPort", "192.168.1.10", 9100) ; Add a printer, give it the name "My Printer", use the driver called "Samsung ML-451x 501x Series" and the port called "MyTCPIPPrinterPort" _PrintMgr_AddPrinter("My Printer", "Samsung ML-451x 501x Series", "MyTCPIPPrinterPort") ; Set the printer called "My Printer" as default printer _PrintMgr_SetDefaultPrinter("My Printer") ; Connect to the shared printer "\\192.168.1.1\HPDeskjetColor") _PrintMgr_AddWindowsPrinterConnection("\\192.168.1.1\HPDeskjetColor") ; List all installed printers #Include <Array.au3> $aPrinterList = _PrintMgr_EnumPrinter() _ArrayDisplay($aPrinterList) ; List all printers configuration #Include <Array.au3> $aPrinterConfig = _PrintMgr_EnumPrinterConfiguration() _ArrayDisplay($aPrinterConfig) ; List all installed printer drivers #Include <Array.au3> $aDriverList = _EnumPrinterDriver() _ArrayDisplay($aDriverList) ; Retrieve the printer configuration for the printer called "Lexmark T640" #Include <Array.au3> $aPrinterConfig = _PrintMgr_EnumPrinterConfiguration("Lexmark T640") _ArrayDisplay($aPrinterConfig) ; Add a local printer port (for a file output) _AddLocalPrinterPort("c:\temp\output.pcl") ; Remove the local port _RemoveLocalPrinterPort("c:\temp\output.pcl") Download link :  PrintMgr.au3
    • jguinch
      By jguinch
      Here is an UDF for managing printers.
      Features are :
       - add, remove or rename a printer
       - add or remove a driver
       - add or remove a TCP/IP printer port
       - add or remove a LPR printer port
       - connect to a remote printer
       - enum printers and there configuration and properties
       - pause resume or cancel all jobs of a printer
       - checks if a printer exists
       - print a test page
       - set the default printer