#include-once Local $_objError = ObjEvent('AutoIt.Error', '_ObjErrorHandler') ; ; popular wmi classes ; ------------------- ; Win32_BaseBoard, Win32_Battery, Win32_BIOS, Win32_CDROMDrive, Win32_ComputerSystem ; Win32_ComputerSystemProduct, Win32_DiskDrive, Win32_DesktopMonitor, Win32_Keyboard ; Win32_LogicalDisk, Win32_NetworkAdapter, Win32_NetworkAdapterConfiguration ; Win32_PhysicalMemory, Win32_OperatingSystem, Win32_PhysicalMedia, Win32_PointingDevice ; Win32_Processor, Win32_SoundDevice, Win32_SystemEnclosure, Win32_VideoController ; ------------------- ; ; ;#FUNCTION# ================================================================================= ;.......Name: _WMI_InstancesOf ;....Version: 2.15 ;.....Author: ripdad ;...........: ------------------------------------------------------------------------------- ;...Released: January 07, 2017 - v2.00 initial release. ;...Modified: January 09, 2017 - v2.01 fixed a problem with WHERE strings. ;...Modified: January 11, 2017 - v2.11 added support for horizontal arrays. ;...Modified: January 12, 2017 - v2.15 changed some code and tweaked a few things. ;...Modified: January 14, 2017 - v2.25 added _Array2D_Swap2Columns. (for horizontal arrays) ;...........: ------------------------------------------------------------------------------- ;Description: This function returns property names of a Class, with their values and ;...........: provides a translation for those values when possible (98% of the time). ;...........: All that is needed is a valid Win32 Class Name. ;...........: ------------------------------------------------------------------------------- ;.Dependency: _ObjErrorHandler() ;...........: ------------------------------------------------------------------------------- ;.Parameters: _WMI_InstancesOf($strClass, $NoBlanks, $nHorizontal, $nStatement, $strProperty) ;...........: ------------------------------------------------------------------------------- ;...........: ($strClass) ;...........: Win32 Class or Win32 Class Plus WHERE/LIKE Statement. ;...........: Example #1: _WMI_InstancesOf('Win32_BIOS') ;...........: Example #2: _WMI_InstancesOf('Win32_BIOS WHERE Status = "OK"') ;...........: Example #3: _WMI_InstancesOf('Win32_BIOS WHERE Status LIKE "%OK%"') ;...........: ------------------------------------------------------------------------------- ;...........: ($NoBlanks) Default = 0 ;...........: 0 = Include blank values. ;...........: 1 = Do not include blank values. ;...........: Example: _WMI_InstancesOf('Win32_BIOS', 1) ;...........: ------------------------------------------------------------------------------- ;...........: ($nHorizontal) Default = 0 ;...........: 0 = Return vertical array ;...........: 1 = Return horizontal array ;...........: ;...........: NOTE: ;...........: $NoBlanks = 0 will be forced internally to ensure matched property sets. ;...........: ;...........: Example: ;...........: Local $sProperties = 'Manufacturer|Name|NetConnectionID|NetConnectionStatus' ;...........: _WMI_InstancesOf('Win32_NetworkAdapter', 0, 1, 1, $sProperties) ;...........: ------------------------------------------------------------------------------- ;...........: ($nStatement) Default = 0. Must be used with ($strProperty). ;...........: 0 = Get all Properties. ;...........: 1 = Get these Properties only. ;...........: 2 = Do not get these Properties. ;...........: ------------------------------------------------------------------------------- ;...........: ($strProperty) Default = 0. Must be used with ($nStatement) ;...........: ;...........: Get Specific Properties. ;...........: Example #1: Single Property: ;...........: _WMI_InstancesOf('Win32_BIOS', 0, 0, 1, 'Manufacturer') ;...........: ;...........: Example #2: Multiple Properties: ;...........: _WMI_InstancesOf('Win32_BIOS', 0, 0, 1, 'Caption|Manufacturer|Version') ;...........: ;...........: Do not get these properties. ;...........: Example #3: ;...........: _WMI_InstancesOf('Win32_BIOS', 0, 0, 2, 'Caption|Description|Status') ;...........: ------------------------------------------------------------------------------- ;....Returns: Success - A populated array. ;...........: Failure - sets @error less than zero. ;...........: ------------------------------------------------------------------------------- ;....Remarks: Sometimes a Class will return an Object Error (usually -4), simply ;...........: because a device or some other issue does not exist. For Example: ;...........: ;...........: With Win32_Battery, If your PC has a UPS and is not USB connected, then ;...........: it will not detect it. WMI will not produce an object for that Class if ;...........: the device cannot be found. There are other situations besides this one. ;...........: ;...........: Certain Classes need specific code in order for them to work. This ;...........: function was not intended to work with those. (Error code -2) ;...........: About 75% of the available Win32 Classes will work. ;...........: ------------------------------------------------------------------------------- ;......Links: Windows Management Instrumentation ;...........: https://msdn.microsoft.com/en-us/library/aa394582(v=vs.85).aspx ;...........: ;...........: WMI_Query v1.04 (resource for wmi class properties and methods) ;...........: https://www.autoitscript.com/forum/topic/139323-wmi-query-v104/ ;============================================================================================ Func _WMI_InstancesOf($strClass, $NoBlanks = 0, $nHorizontal = 0, $nStatement = 0, $strProperty = 0) Local $sClass = StringRegExpReplace($strClass, '(\W.*)', '') If StringLeft($sClass, 5) <> 'Win32' Then Return SetError(-1, 0, 'Not Supported - Win32 Classes Only') ElseIf StringRegExp($sClass, '(?i)(Action|Check|Directory|File|Specification)') Then Return SetError(-2, 0, 'Not Supported - Needs Specific Code') EndIf ; Local $objWMI = ObjGet('Winmgmts:root\CIMV2') Local $objItems = $objWMI.InstancesOf($strClass) If @error Or Not IsObj($objItems) Then Return SetError(-3, 0, 'Object Error - Invalid Class String') EndIf ; Local $NumberOfObjects = Number($objItems.Count) If @error Or $NumberOfObjects < 1 Then Return SetError(-4, 0, 'Object Not Found - No Data Available') EndIf ; Local $objClass = $objWMI.Get($sClass, 0x20000); <- wbemFlagUseAmendedQualifiers If @error Or Not IsObj($objClass) Then Return SetError(-5, 0, 'Object Error - Invalid Class Name') EndIf ; Local $NumberOfProperties = Number($objClass.Properties_().Count) If @error Or $NumberOfProperties < 1 Then Return SetError(-6, 0, 'Object Error - No Property Count') EndIf ; ; (added in v2.15) If $nHorizontal <> 0 Then; <- horizontal array - force settings to ensure matched Property Sets $nHorizontal = 1 $NoBlanks = 0 EndIf ; Local $IDX = ($NumberOfProperties * $NumberOfObjects) + $NumberOfObjects ; (changed in v2.15) If $IDX > 65525 Then; <- array viewing limt exceeded - force settings to ensure below the limit. (only effects 1 or 2 Win32 COM classes) $nHorizontal = 0; <- because $NoBlanks = 1, we cannot allow horizontal arrays, otherwise a mismatch will occur. $NoBlanks = 1 EndIf ; If $nStatement = 1 Or $nStatement = 2 Then Local $aProperty = StringSplit($strProperty, '|') For $i = 1 To $aProperty[0] If Not StringLen(StringStripWS($aProperty[$i], 8)) Then Return SetError(-7, 0, 'Invalid $strProperty Parameter') ElseIf StringRegExp($aProperty[$i], '(\W)') Then Return SetError(-8, 0, 'Invalid Character In $strProperty') EndIf Next $strProperty = StringReplace($strProperty, '|', '\b)|(\b') EndIf ; Local $aBitMap, $aBitValues, $aValueMap, $aValues, $QualifierName, $QualifierValue Local $IsArrayValue, $sPropertyName, $xPropertyValue, $str, $n = 0 Local $a[$IDX + 1][2] = [[$IDX, $sClass]] ; For $objItem In $objItems For $objProperty In $objItem.Properties_() $sPropertyName = $objProperty.Name ; If StringRegExp($sPropertyName, '(?i)(\bCreationClassName\b)|(\bCSCreationClassName\b)|(\bSystemCreationClassName\b)|(\bSystemName\b)') Then ContinueLoop; remove repetitive property names EndIf ; $xPropertyValue = $objProperty.Value; <- value can be an array or number or string $IsArrayValue = IsArray($xPropertyValue) ; If $NoBlanks = 1 And Not $IsArrayValue And Not StringLen(StringStripWS($xPropertyValue, 8)) Then ContinueLoop; skip blank values EndIf ; If $nStatement = 1 Then; get these properties only If StringRegExp($sPropertyName, '(?i)(\b' & $strProperty & '\b)') = 0 Then ContinueLoop EndIf ElseIf $nStatement = 2 Then; do not get these properties If StringRegExp($sPropertyName, '(?i)(\b' & $strProperty & '\b)') = 1 Then ContinueLoop EndIf EndIf ; $n += 1 $a[$n][0] = $sPropertyName ; If $IsArrayValue Then If Not UBound($xPropertyValue) Then; <- no elements $a[$n][1] = -2; <- represents an error for this property value ContinueLoop EndIf ElseIf Not StringLen(StringStripWS($xPropertyValue, 8)) Then $a[$n][1] = '---'; <- no value found ContinueLoop ElseIf StringIsDigit($xPropertyValue) Then $xPropertyValue = Number($xPropertyValue); <- convert to hard number EndIf ; ;<- Start Translation For $objQualifier In $objClass.Properties_($sPropertyName).Qualifiers_() $QualifierName = $objQualifier.Name $QualifierValue = $objQualifier.Value ; Switch $QualifierName Case 'CIMTYPE' If $QualifierValue = 'DateTime' Then $xPropertyValue = StringRegExpReplace($xPropertyValue, '(....)(..)(..)(..)(..)(..).*', '$1/$2/$3 - $4:$5:$6') ExitLoop EndIf Case 'Units' If StringInStr($QualifierValue, 'Bytes') Then Local $nOffset = UBound(StringRegExp($QualifierValue, '(?i)(\bBytes\b)|(\bKiloBytes\b)', 3)) Local $aBytes = StringSplit('Bytes|KB|MB|GB|TB', '|') For $i = $nOffset To $aBytes[0] If $xPropertyValue < 1024 Then $xPropertyValue = Round($xPropertyValue, 2) & ' ' & $aBytes[$i] ExitLoop 2 EndIf $xPropertyValue /= 1024 Next Else; <- bits, hertz, percent, etc. $xPropertyValue &= ' ' & $QualifierValue ExitLoop EndIf Case 'Values' $aValues = $QualifierValue Case 'ValueMap' $aValueMap = $QualifierValue Case 'BitValues' $aBitValues = $QualifierValue Case 'BitMap' $aBitMap = $QualifierValue Case Else EndSwitch Next ; ; There are 5 possible arrays at this point. Only 3 or less are used at a time. ; We have to figure out which ones have the data -- None or a combination of them. ; If Not $IsArrayValue And Not StringIsDigit($xPropertyValue) Then; <- $xPropertyValue is a string ; pass through ElseIf $IsArrayValue And Not StringIsDigit($xPropertyValue[0]) Then; <- $xPropertyValue is an array and has strings For $i = 0 To UBound($xPropertyValue) - 1 $str &= $xPropertyValue[$i] & ', ' Next ElseIf $IsArrayValue Then; <- $xPropertyValue is an array with numbers in this first set of Cases Select Case IsArray($aValueMap) And IsArray($aValues); <- 3 arrays, includes $xPropertyValue For $i = 0 To UBound($aValueMap) - 1 For $j = 0 To UBound($xPropertyValue) - 1 If Number($aValueMap[$i]) = Number($xPropertyValue[$j]) Then $str &= $aValues[$i] & ', ' EndIf Next Next If StringRight($str, 2) <> ', ' Then; <- backup measure For $i = 0 To UBound($xPropertyValue) - 1 $str &= $xPropertyValue[$i] & ', ' Next EndIf Case IsArray($aValues); <- 2 arrays, includes $xPropertyValue For $i = 0 To UBound($xPropertyValue) - 1 If Number($xPropertyValue[$i]) < UBound($aValues) Then $str &= $aValues[$xPropertyValue[$i]] & ', ' EndIf Next If StringRight($str, 2) <> ', ' Then; <- backup measure ContinueCase EndIf Case Else; <- 1 array For $i = 0 To UBound($xPropertyValue) - 1 $str &= $xPropertyValue[$i] & ', ' Next EndSelect Else; <- $xPropertyValue is a number in this second set of Cases. Select Case IsArray($aValueMap) And IsArray($aValues); <- 2 arrays For $i = 0 To UBound($aValueMap) - 1 If Number($aValueMap[$i]) = $xPropertyValue Then $xPropertyValue = $aValues[$i] ExitLoop EndIf Next Case IsArray($aBitMap) And IsArray($aBitValues); <- 2 arrays For $i = 0 To UBound($aBitMap) - 1 If BitAND($xPropertyValue, $aBitMap[$i]) And $i <= UBound($aBitValues) Then $xPropertyValue = $aBitValues[$i] ExitLoop EndIf Next Case IsArray($aBitValues); <- 1 array Local $b = StringSplit('1|2|4|8|16|32|64|128|256|512|1024|2048|4096', '|') For $i = 1 To $b[0] If BitAND($xPropertyValue, Number($b[$i])) And $i <= UBound($aBitValues) Then $xPropertyValue = $aBitValues[$i - 1] ExitLoop EndIf Next Case IsArray($aValues); <- 1 array If $xPropertyValue <= UBound($aValues) Then $xPropertyValue = $aValues[$xPropertyValue] EndIf Case Else; <- no arrays - number only ; pass through EndSelect EndIf ; If StringRight($str, 2) = ', ' Then $xPropertyValue = StringTrimRight($str, 2) EndIf $xPropertyValue = StringReplace($xPropertyValue, @TAB, ' - ') $a[$n][1] = StringStripWS($xPropertyValue, 7) ;<- End Translation ; ; reset vars $aBitValues = '' $aValueMap = '' $aBitMap = '' $aValues = '' $str = '' Next $n += 1 $a[$n][0] = '==============='; <- separator for multiple instances Next ReDim $a[$n][2] $a[0][0] = $n - 1 ; If $nHorizontal <> 1 Then Return $a EndIf ; ; <- convert to horizontal array (added in 2.11) Local $nColumns = 0 For $i = 1 To $a[0][0] If StringLeft($a[$i][0], 1) = '=' Then; <- find the first separator $nColumns = $i - 1; <- get number of properties minus the separator ExitLoop EndIf Next ; ; A Property Set is the number of properties between two separators. ; If a Property Set is larger or smaller than the first Set, then ; this function cannot proceed any further because of the mismatch. ; If $nColumns > 0 Then; <- multiple Property Sets For $i = $nColumns + 1 To $a[0][0] Step $nColumns + 1 If StringLeft($a[$i][0], 1) <> '=' Then Return SetError(-9, 0, 'Property Sets Not Matched') EndIf Next Else $nColumns = $a[0][0]; <- single Property Set EndIf ; Local $nRows = Round($a[0][0] / $nColumns) + 1 Local $aHorizontal[$nRows][$nColumns] ; For $i = 0 To $nColumns - 1 $aHorizontal[0][$i] = $a[$i + 1][0]; <- insert headers Next ; $nRows = 0 For $i = 1 To $a[0][0] Step $nColumns + 1 $nRows += 1 For $j = 0 To $nColumns - 1 $aHorizontal[$nRows][$j] = $a[$i + $j][1]; <- insert data Next Next ; ReDim $aHorizontal[$nRows + 1][$nColumns] Return $aHorizontal EndFunc ; Func _ObjErrorHandler($_objError) $_objError.Clear Return SetError(1) EndFunc ; ;============================================================= ; Example: _Array2D_Swap2Columns($array, 0, 1) ;============================================================= Func _Array2D_Swap2Columns(ByRef $array, $nColumn1, $nColumn2) Local $nUBound = UBound($array, 2) If $nUBound = 0 Then Return SetError(-1) ElseIf $nColumn1 > $nUBound Or $nColumn2 > $nUBound Then Return SetError(-2) ElseIf $nColumn1 < 0 Or $nColumn2 < 0 Then Return SetError(-3) EndIf ; Local $ContentsOfColumnCell For $i = 0 To UBound($array) - 1 $ContentsOfColumnCell = $array[$i][$nColumn1] $array[$i][$nColumn1] = $array[$i][$nColumn2] $array[$i][$nColumn2] = $ContentsOfColumnCell Next EndFunc ;