Jump to content
TheAppleFreak

WMI "ASSOCIATORS OF" query ridiculously slower when running as Administrator than when running as a standard user

Recommended Posts

TheAppleFreak

Never experienced anything like this before, so to you I come for help...

I'm in the process of rewriting my fork of JSThePatriot's excellent Computer Information library, and my current project is rewriting the User profiling function. One of the new features I've added in is gathering the list of groups a particular user profile belongs to, which uses an existing WMI object to run an "ASSOCIATORS OF" query targeting the specified domain and username. 

When I run the function under my own user account from within ISN/ScITE or compile it and run it via Windows Explorer, my test script collects the information in a fraction of a second. When I compile the script and Right Click -> "Run As Administrator," the script takes almost three and a half minutes to complete. It's literally the exact same code, but running under Administrator has a computed 6320x slowdown. Examining the script running in Process Monitor showed no activity during what I assume are these queries, which boggles my mind. 

If someone could tell me what I'm doing wrong, that'd be super awesome. Below is the code used, and below that is a log file that I generated to root out what in particular was causing the massive slowdown. It's worth mentioning that I'm currently running Windows 8.1 on this machine, under a user account that is part of both the Administrators and Users groups. 

; From CompInfoObject.au3
; =========================

#include <File.au3>
#include <Array.au3>
#include <Security.au3>

#region Global Variables and Constants
If Not(IsDeclared("$cI_CompName")) Then
    Global $cI_CompName = @ComputerName
EndIf
Global Const $cI_VersionInfo        = "00.03.08"
Global Const $cI_aName              = 0, _
             $cI_aDesc              = 4
Global  $wbemFlagReturnImmediately  = 0x10, _   ;DO NOT CHANGE
$wbemFlagForwardOnly        = 0x20              ;DO NOT CHANGE
Global  $ERR_NO_INFO                = "Array contains no information", _
        $ERR_NOT_OBJ                = "$colItems isnt an object"

Global Const $VERSION_CIO = "2.1.0.0"
#endregion Global Variables and Constants

; Test script
; ==========================

Global Const $logPath = "D:\logFile.txt"

If IsAdmin() Then 
    FileWriteLine($logPath, "============= RUNNING AS ADMINISTRATOR ============")
Else 
    FileWriteLine($logPath, "================= RUNNING AS USER =================")
EndIf
FileWriteLine($logPath, "")


FileWriteLine($logPath, "Starting user profiling...")
FileWriteLine($logPath, "")
Local $runtime = TimerInit()
Local $test = _ComputerGetUsers()
FileWriteLine($logPath, "User profiling complete after " & (TimerDiff($runtime) / 1000) & " seconds")
FileWriteLine($logPath, "")

MsgBox(0, "", "complete", 10)

; From CompInfoObject.au3

Func _ComputerGetUsers()
    Local $localSIDs[1]
    Local $i = 0, $x = 1, $sid
    
    While 1
        $sid = RegEnumKey("HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList", $x)
        If @error Then ExitLoop
        
        If StringInStr($sid, "S-1-5-21-") Then 
            If IsArray(_Security__LookupAccountSid($sid)) Then
                ReDim $localSIDs[$i + 1]
                $localSIDs[$i] = $sid
                
                $i += 1
            EndIf 
        EndIf
        
        $x += 1
    Wend
    
    $i = 0
    _ArraySort($localSIDs)
    
    Local $colItems, $objWMIService, $objItem, $wqlQuery
    Local $groups, $userProfile, $userProfileLoaded, $regMountPoint, $runtime
    Local $users[1] = [ObjCreate("Scripting.Dictionary")]
    
    $wqlQuery = "SELECT * FROM Win32_UserAccount"

    $objWMIService = ObjGet("winmgmts:\\" & $cI_Compname & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery($wqlQuery, "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    If IsObj($colItems) Then
        For $objItem In $colItems
            ; Restrict users to actual users on the computer
            If _ArrayBinarySearch($localSIDs, $objItem.SID) <> -1 Then 
                FileWriteLine($logPath, "Collecting basic information for " & $objItem.Name & "...")
                $runtime = TimerInit()
                
                $regMountPoint = Null 
                $userProfileLoaded = False
                
                ReDim $users[$i + 1]
                $users[$i] = ObjCreate("Scripting.Dictionary")
                $users[$i].Add("Name", StringStripWS($objItem.Name, 3))
                $users[$i].Add("Domain", StringStripWS($objItem.Domain, 3))
                $users[$i].Add("Status", StringStripWS($objItem.Status, 3))
                $users[$i].Add("FullName", StringStripWS($objItem.FullName, 3))
                $users[$i].Add("Description", StringStripWS($objItem.Description, 3))
                $users[$i].Add("SID", StringStripWS($objItem.SID, 3))
                $users[$i].Add("Disabled", $objItem.Disabled)
                $users[$i].Add("Lockout", $objItem.Lockout)
                $users[$i].Add("PasswordChangeable", $objItem.PasswordChangeable)
                $users[$i].Add("PasswordExpires", $objItem.PasswordExpires)
                $users[$i].Add("PasswordRequired", $objItem.PasswordRequired)
                
                FileWriteLine($logPath, "Finished collecting basic information for " & $users[$i].Item("Name") & " in " & (TimerDiff($runtime) / 1000) & " seconds")
                FileWriteLine($logPath, "")
                
                ; Get user group membership
                FileWriteLine($logPath, "Collecting group information for " & $users[$i].Item("Name") & "...")
                $runtime = TimerInit()
                
                $groups = $objWMIService.ExecQuery("ASSOCIATORS OF {Win32_UserAccount.Domain='" & $objItem.Domain & "',Name='" & $objItem.Name & "'} WHERE ResultClass=Win32_Group", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
                
                If IsObj($groups) Then 
                    Local $temp[1]
                    $x = 0
                    
                    For $group in $groups
                        ReDim $temp[$x + 1]
                        $temp[$x] = ObjCreate("Scripting.Dictionary")
                        
                        $temp[$x].Add("Name", $group.Name)
                        $temp[$x].Add("Domain", $group.Domain)
                        $temp[$x].Add("SID", $group.SID)
                        
                        $x += 1
                    Next
                    
                    $users[$i].Add("Groups", $temp)
                EndIf
                
                FileWriteLine($logPath, "Finished collecting group information for " & $users[$i].Item("Name") & " in " & (TimerDiff($runtime) / 1000) & " seconds")
                FileWriteLine($logPath, "")
                
                #cs 
                ; First, we need to mount the registry before anything else, or get the registry path if it already is
                $userProfile = $objWMIService.ExecQuery("SELECT * FROM Win32_UserProfile WHERE SID=""" & $users[$i].Item("SID") & """", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
                
                If IsObj($userProfile) Then                 
                    For $profile in $userProfile
                        $users[$i].Add("ProfilePath", StringStripWS($profile.LocalPath, 3))
                        
                        If $profile.Loaded Then 
                            $userProfileLoaded = True 
                            $regMountPoint = "HKEY_USERS\" & $users[$i].Item("SID") & "\"
                        EndIf
                        ExitLoop
                    Next
                    
                    ; Profile isn't loaded. Load it manually. 
                    If $regMountPoint == Null Then
                        If RunWait("reg load HKU\TEMP-&" & $users[$i].Item("SID") & " " & $users[$i].Item("ProfilePath") & "\NTUSER.dat") == 0 Then 
                            MsgBox(0, "", "Loaded registry hive for " & $users[$i].Item("Name") & @CRLF, 3)
                            $regMountPoint = "HKEY_USERS\TEMP-" & $users[$i].Item("SID") & "\"
                        Else 
                            MsgBox(0, "", "Failed to load registry hive for " & $users[$i].Item("Name") & @CRLF, 3)
                        EndIf
                    EndIf
                EndIf
                
                ; Get user's mapped file shares
                ; HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\
                ; Run regex "\#\#(.+?)\#(.+?)" to get path, then read key _LabelFromReg for any custom drive label applied
                

                ; Get user's mapped printers
                ; https://support.microsoft.com/en-us/kb/102966
                
                
                ; Unload profile if it wasn't previously loaded
                If Not $userProfileLoaded And $regMountPoint <> Null Then 
                    If RunWait("reg unload " & StringRegExp($regMountPoint, "^(.*)\\$", 1)[0]) Then 
                        MsgBox(0, "", "Unloaded registry hive at " & $regMountPoint & @CRLF, 3)
                    Else 
                        MsgBox(0, "", "Error: Could not unload registry hive at " & $regMountPoint & @CRLF, 3)
                    EndIf
                EndIf
                #ce 
                
                $i += 1
            EndIf
        Next
        If $users[Ubound($users) - 1].Count < 1 Then
            ReDim $users[Ubound($users) - 1]
        EndIf
        If Ubound($users) < 1 Then
            Return SetError(1, 1, 0)
        EndIf
    Else 
        Return SetError(1, 2, 0)
    EndIf
    
    Return $users 
EndFunc

And here's the log file:

================= RUNNING AS USER =================

Starting user profiling...

Collecting basic information for Administrator...
Finished collecting basic information for Administrator in 0.000332286438607835 seconds

Collecting group information for Administrator...
Finished collecting group information for Administrator in 0.0347993066888362 seconds

Collecting basic information for <redacted>...
Finished collecting basic information for <redacted> in 0.00030855169299299 seconds

Collecting group information for <redacted>...
Finished collecting group information for <redacted> in 0.0321612217877267 seconds

User profiling complete after 0.1464664737096 seconds

============= RUNNING AS ADMINISTRATOR ============

Starting user profiling...

Collecting basic information for Administrator...
Finished collecting basic information for Administrator in 0.000270383656125874 seconds

Collecting group information for Administrator...
Finished collecting group information for Administrator in 27.3050492143158 seconds

Collecting basic information for <redacted>...
Finished collecting basic information for <redacted> in 0.000575407211257197 seconds

Collecting group information for <redacted>...
Finished collecting group information for <redacted> in 203.270754752081 seconds

User profiling complete after 230.621668475639 seconds

 

Edited by TheAppleFreak

Share this post


Link to post
Share on other sites
TheAppleFreak

Many, many thanks for that link! While I can't see the link on its own being incredibly useful, it did remind me of the existence of Win32_GroupUser, which a quick Google search for yielded a wealth of information that looks to be incredibly useful. 

Once I get to my computer, I'll do some testing to see what performance is like; hopefully this should help significantly. 

Share this post


Link to post
Share on other sites
AdamUL

Your welcome.  Glad it help.  

 

Adam

Share this post


Link to post
Share on other sites
TheAppleFreak

As an update for those who might stumble across this later on:

I haven't figured out why the Associators query runs so slowly under an Administrator account, but I did rework my queries to accomplish roughly the same task. As a warning, this method will perform more queries than you'd use otherwise, and it's likely not the fastest way to do this, but it does works properly under both a standard user and an administrator account (tested on Windows 7 and Windows 8.1).

The Win32_GroupUser class is composed of two properties, GroupComponent and PartComponent. GroupComponent is a link to the specified group, and PartComponent is a link to the specified user. Since I'm not good enough yet with my WMI-fu to just get the object at the link directly, I'm instead constructing a WMI query to find any entries that match the user I specify (identified by domain and username). Using the Win32_UserAccount object for the user I'm looking up, my query looks something like this:

Local $objGroupMaps = $objWMIService.ExecQuery("SELECT GroupComponent FROM Win32_GroupUser WHERE PartComponent=""Win32_UserAccount.Domain='" & $objItem.Domain & "',Name='" & $objItem.Name & "'""", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

It's worth noting you can reverse this (search by GroupComponent instead of PartComponent) so you can enumerate all users in a group.

Following that, I iterate through the list of return group mappings and run a regular expression on the GroupComponent property to extract the domain and name of the group from the map string. If all you're looking for is the domain and name of the group, you can stop here, but I want to get a little more information from the group, so I run another WMI query to get that. 

For $objGroupMap in $objGroupMaps
    $aParams = StringRegExp($groupMap.GroupComponent, "^.*?(?<=Win32_Group\.)(.*?),(.*?)$", 1)
    
    ; It should return only one entry, so the name $groups probably isn't the best choice, but I
    ; iterate through it like any other object collection.
    ; If anyone has a better idea what to call this, I'm all ears
    Local $groups = $objWMIService.ExecQuery("SELECT * FROM Win32_Group WHERE " & $aParams[0] & " AND " & $aParams[1], "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    
    If IsObj($groups) Then 
        For $group in $groups
            ...
        Next
    EndIf
Next

It's obviously not as performant as running the "ASSOCIATORS OF" query under a standard user, but execution time remains very similar when running as an administrator, which is what I want. I will admit I also had an issue with this query where on my development machine it wasn't returning the local administrator's profile information, though I think that might be an unrelated issue. Yep, completely unrelated issue.

I hope this helps somebody!

Edited by TheAppleFreak

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

    • leomoon
      By leomoon
      Hello,
      I'm having trouble getting information from Win32_Processor:
      https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-processor
      How does this WMI Query work? Let's say I need to query VMMonitorModeExtensions, Level, ProcessorId, and ProcessorType.
      How would this work?
      Thanks.
    • colombeen
      By colombeen
      Hi everyone, I created a function to gather bitlocker information. It can tell you whether or not a drive is protected, which encryption method is being used, ...
      I tried to cover all the details in the function description
       
      The function (and 3 "internal" functions) :
      ; #FUNCTION# ==================================================================================================================== ; Name...........: _BitlockerDriveInfo ; Description ...: Get Bitlocker information for one or multiple drives ; Syntax.........: _BitlockerDriveInfo([$sDrive[, $sComputer = @ComputerName[, $bDebug = False]]]) ; Parameters ....: $sDrive - Optional: The drive. Allowed values are: ; |"" - Get the info for all available drives ; |Letter: - Get the info for the specific drive ; $sComputer - Optional: The computer from which the info should be requested ; $bDebug - Optional: Shows the hex ReturnValue from the WMI methods if set to True ; Return values .: Success - Returns a 2D array with the following information ; |[string] Drive Letter ; |[string] Drive Label ; |[string] Volume Type ; |[bool] Initialized For Protection ; |[string] Protection Status ; |[string] Lock Status ; |[bool] Auto Unlock Enabled ; |[bool] Auto Unlock Key Stored ; |[string] Conversion Status ; |[string] Encryption Method ; |[int] Encryption Percentage ; |[string] Wiping Status ; |[int] Wiping Percentage ; |[array] Key Protectors (Or [string] "None" if the drive isn't protected) ; Failure - 0, sets @error to: ; |1 - There was an issue retrieving the COM object. @extended returns error code from ObjGet ; |2 - The specified drive in $Drive doesn't exist ; |3 - There was an issue running the WMI query ; Author ........: colombeen ; Modified.......: ; Remarks .......: Requires to be run with admin elevation. Windows Vista or newer! ; A BIG THANKS to everyone from the community who contributed! ; Related .......: ; Link ..........: ; Example .......: #include <Array.au3> ; $Header = "Drive Letter|Drive Label|Volume Type|Initialized For Protection|Protection Status|" & _ ; "Lock Status|Auto Unlock Enabled|Auto Unlock Key Stored|Conversion Status|Encryption " & _ ; "Method|Encryption Percentage|Wiping Status|Wiping Percentage|Key Protectors" ; _ArrayDisplay(_BitlockerDriveInfo(), "Bitlocker Drive Info", "", 64, Default, $Header) ; =============================================================================================================================== Func _BitlockerDriveInfo($sDrive = "", $sComputer = @ComputerName, $bDebug = False) Local $aConversionStatusMsg[7] = ["Unknown", "Fully Decrypted", "Fully Encrypted", "Encryption In Progress", "Decryption In Progress", "Encryption Paused", "Decryption Paused"] Local $aEncryptionMethodMsg[9] = ["Unknown", "None", "AES_128_WITH_DIFFUSER", "AES_256_WITH_DIFFUSER", "AES_128", "AES_256", "HARDWARE_ENCRYPTION", "XTS_AES_128", "XTS_AES_256"] Local $aKeyProtectorTypeMsg[11] = ["Unknown or other protector type", "Trusted Platform Module (TPM)", "External key", "Numerical password", "TPM And PIN", "TPM And Startup Key", "TPM And PIN And Startup Key", "Public Key", "Passphrase", "TPM Certificate", "CryptoAPI Next Generation (CNG) Protector"] Local $aLockStatusMsg[3] = ["Unknown", "Unlocked", "Locked"] Local $aProtectionStatusMsg[3] = ["Unprotected", "Protected", "Unknown"] Local $aVolumeTypeMsg[3] = ["Operating System Volume", "Fixed Data Volume", "Portable Data Volume"] Local $aWipingStatusMsg[5] = ["Unknown", "Free Space Not Wiped", "Free Space Wiped", "Free Space Wiping In Progress", "Free Space Wiping Paused"] Local $iRow = 0 Local $sRunMethod, $objWMIService, $objWMIQuery, $sDriveFilter, $iProtectionStatus, $iLockStatus, $bIsAutoUnlockEnabled, $bIsAutoUnlockKeyStored, $iConversionStatus, $iEncryptionPercentage, $iEncryptionFlags, $iWipingStatus, $iWipingPercentage, $iEncryptionMethod, $aVolumeKeyProtectorID, $aVolumeKeyProtectors, $iKeyProtectorType $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & "\root\CIMV2\Security\MicrosoftVolumeEncryption") If @error Then Return SetError(1, @error, 0) If $sDrive <> "" Then Local $iDriveType = _WMIPropertyValue("DriveType", "Win32_LogicalDisk", "WHERE DeviceID='" & $sDrive & "'", Default, $sComputer) If @error Or ($iDriveType <> 2 And $iDriveType <> 3) Then Return SetError(2, 0, 0) $sDriveFilter = " WHERE DriveLetter='" & $sDrive & "'" EndIf $objWMIQuery = $objWMIService.ExecQuery("SELECT * FROM Win32_EncryptableVolume" & $sDriveFilter, "WQL", 0) If Not IsObj($objWMIQuery) Then Return SetError(3, 0, 0) Local $aResult[$objWMIQuery.count][14] For $objDrive In $objWMIQuery If $bDebug Then ConsoleWrite(@CRLF & "+> " & $objDrive.DriveLetter & @CRLF) If _WMIMethodExists($objDrive, "GetConversionStatus") Then $sRunMethod = $objDrive.GetConversionStatus($iConversionStatus, $iEncryptionPercentage, $iEncryptionFlags, $iWipingStatus, $iWipingPercentage) If $bDebug Then ConsoleWrite("!> GetConversionStatus 0x" & Hex($sRunMethod) & @CRLF) Else $iConversionStatus = -1 $iWipingStatus = -1 $iEncryptionPercentage = 0 $iWipingPercentage = 0 EndIf If _WMIMethodExists($objDrive, "GetEncryptionMethod") Then $sRunMethod = $objDrive.GetEncryptionMethod($iEncryptionMethod) If $bDebug Then ConsoleWrite("!> GetEncryptionMethod 0x" & Hex($sRunMethod) & @CRLF) Else $iEncryptionMethod = 0 EndIf If _WMIMethodExists($objDrive, "GetKeyProtectors") Then $sRunMethod = $objDrive.GetKeyProtectors("0", $aVolumeKeyProtectorID) If $bDebug Then ConsoleWrite("!> GetKeyProtectors 0x" & Hex($sRunMethod) & @CRLF) Else $aVolumeKeyProtectorID = 0 EndIf If _WMIMethodExists($objDrive, "GetLockStatus") Then $sRunMethod = $objDrive.GetLockStatus($iLockStatus) If $bDebug Then ConsoleWrite("!> GetLockStatus 0x" & Hex($sRunMethod) & @CRLF) Else $iLockStatus = -1 EndIf If _WMIMethodExists($objDrive, "GetProtectionStatus") Then $sRunMethod = $objDrive.GetProtectionStatus($iProtectionStatus) If $bDebug Then ConsoleWrite("!> GetProtectionStatus 0x" & Hex($sRunMethod) & @CRLF) Else $iProtectionStatus = 2 EndIf If _WMIMethodExists($objDrive, "IsAutoUnlockEnabled") Then $sRunMethod = $objDrive.IsAutoUnlockEnabled($bIsAutoUnlockEnabled) If $bDebug Then ConsoleWrite("!> IsAutoUnlockEnabled 0x" & Hex($sRunMethod) & @CRLF) Else $bIsAutoUnlockEnabled = "Unknown" EndIf If _WMIMethodExists($objDrive, "IsAutoUnlockKeyStored") Then $sRunMethod = $objDrive.IsAutoUnlockKeyStored($bIsAutoUnlockKeyStored) If $bDebug Then ConsoleWrite("!> IsAutoUnlockKeyStored 0x" & Hex($sRunMethod) & @CRLF) Else $bIsAutoUnlockKeyStored = "Unknown" EndIf If IsArray($aVolumeKeyProtectorID) And UBound($aVolumeKeyProtectorID) > 0 Then Dim $aVolumeKeyProtectors[UBound($aVolumeKeyProtectorID)][2] For $i = 0 To UBound($aVolumeKeyProtectorID) - 1 $aVolumeKeyProtectors[$i][0] = $aVolumeKeyProtectorID[$i] If _WMIMethodExists($objDrive, "GetKeyProtectorType") Then If $objDrive.GetKeyProtectorType($aVolumeKeyProtectorID[$i], $iKeyProtectorType) = 0 Then $aVolumeKeyProtectors[$i][1]= $aKeyProtectorTypeMsg[$iKeyProtectorType] Else $aVolumeKeyProtectors[$i][1]= "Unknown" EndIf Else $aVolumeKeyProtectors[$i][1] = "Unknown" EndIf Next Else $aVolumeKeyProtectors = "None" EndIf ; DriveLetter $aResult[$iRow][0] = $objDrive.DriveLetter ; DriveLabel $aResult[$iRow][1] = _WMIPropertyValue("VolumeName", "Win32_LogicalDisk", "WHERE DeviceID='" & $objDrive.DriveLetter & "'", Default, $sComputer) ; VolumeType If _WMIPropertyExists($objDrive, "VolumeType") Then $aResult[$iRow][2] = $aVolumeTypeMsg[$objDrive.VolumeType] Else If $objDrive.DriveLetter = _WMIPropertyValue("SystemDrive", "Win32_OperatingSystem", "", Default, $sComputer) Then $aResult[$iRow][2]= $aVolumeTypeMsg[0] ElseIf _WMIPropertyValue("DriveType", "Win32_LogicalDisk", "WHERE DeviceID='" & $objDrive.DriveLetter & "'", Default, $sComputer) = 3 Then $aResult[$iRow][2]= $aVolumeTypeMsg[1] ElseIf _WMIPropertyValue("DriveType", "Win32_LogicalDisk", "WHERE DeviceID='" & $objDrive.DriveLetter & "'", Default, $sComputer) = 2 Then $aResult[$iRow][2]= $aVolumeTypeMsg[2] Else $aResult[$iRow][2]= "Unknown" EndIf EndIf ; IsVolumeInitializedForProtection If _WMIPropertyExists($objDrive, "IsVolumeInitializedForProtection") Then $aResult[$iRow][3] = $objDrive.IsVolumeInitializedForProtection Else $aResult[$iRow][3] = "Unkown" EndIf ; ProtectionStatus $aResult[$iRow][4] = $aProtectionStatusMsg[$iProtectionStatus] ; LockStatus $aResult[$iRow][5] = $aLockStatusMsg[$iLockStatus + 1] ; IsAutoUnlockEnabled $aResult[$iRow][6] = $bIsAutoUnlockEnabled ; IsAutoUnlockEnabled $aResult[$iRow][7] = $bIsAutoUnlockKeyStored ; ConversionStatus $aResult[$iRow][8] = $aConversionStatusMsg[$iConversionStatus + 1] ; EncryptionMethod $aResult[$iRow][9] = $aEncryptionMethodMsg[$iEncryptionMethod + 1] ; EncryptionPercentage $aResult[$iRow][10] = $iEncryptionPercentage ; WipingStatus $aResult[$iRow][11] = $aWipingStatusMsg[$iWipingStatus + 1] ; WipingPercentage $aResult[$iRow][12] = $iWipingPercentage ; KeyProtectors $aResult[$iRow][13] = $aVolumeKeyProtectors $iRow += 1 Next _ArraySort($aResult) Return $aResult EndFunc ;==>_BitlockerDriveInfo Func _WMIPropertyExists($Object, $Property) If Not IsObj($Object) Then Return False For $sProperty In $Object.Properties_ If $sProperty.Name = $Property Then Return True Next Return False EndFunc ;==>_WMIPropertyExists Func _WMIMethodExists($Object, $Method) If Not IsObj($Object) Then Return False For $sMethod In $Object.Methods_ If $sMethod.Name = $Method Then Return True Next Return False EndFunc ;==>_WMIMethodExists Func _WMIPropertyValue($sProperty = "", $sClass = "", $sFilter = "", $sNamespace = Default, $sComputer = @ComputerName) Local $objWMIService, $objWMIQuery If $sClass = "" Or $sProperty = "" Then Return SetError(1, 0, 0) If $sFilter <> "" Then $sFilter = " " & $sFilter If $sNamespace = Default Then $sNamespace = "\root\CIMV2" $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & $sNamespace) If @error Then Return SetError(2, @error, 0) $objWMIQuery = $objWMIService.ExecQuery("SELECT * FROM " & $sClass & $sFilter, "WQL", 0x30) If Not IsObj($objWMIQuery) Then Return SetError(3, 0, 0) For $objItem In $objWMIQuery For $Property In $objItem.Properties_ If $Property.Name = $sProperty Then Return $Property.Value EndIf Next Next Return SetError(4, 0, 0) EndFunc ;==>_WMIPropertyValue  
      Example 1:
      #RequireAdmin #include <array.au3> ; Get information on all available drives Global $test = _BitlockerDriveInfo() If @error Then ConsoleWrite("!> _BitlockerDriveInfo() error: " & @error & ". extended: " & @extended & @CRLF) ElseIf IsArray($test) Then _ArrayDisplay($test, "Bitlocker Drive Info", "", 64, Default, "Drive Letter|Drive Label|Volume Type|Initialized For Protection|Protection Status|Lock Status|Auto Unlock Enabled|Auto Unlock Key Stored|Conversion Status|Encryption Method|Encryption Percentage|Wiping Status|Wiping Percentage|Key Protectors") ; Display the Key Protectors for the first record If IsArray($test[0][13]) Then _ArrayDisplay($test[0][13]) EndIf Example 2:
      #RequireAdmin #include <array.au3> ; Get information on the C-drive of the current computer + show extra information in the console Global $test = _BitlockerDriveInfo("C:", @ComputerName, True) If @error Then ConsoleWrite("!> _BitlockerDriveInfo() error: " & @error & ". extended: " & @extended & @CRLF) ElseIf IsArray($test) Then ConsoleWrite("Bitlocker information on the " & $test[0][0] & " drive" & @CRLF) ConsoleWrite("Protection Status: " & $test[0][4] & @CRLF) EndIf  
      Screenshot for the first example:

       
      Suggestions? Bugs?
      Just let me know
       
      TODO:
      ???  
      Version 1.0:
      Initial release Version 1.1:
      Fixed: Drive Label will not work when you request the information from a remote system (currently using DriveGetLabel) Fixed: The current fix for the missing VolumeType property in some Windows versions will only work locally Added: New internal function (_WMIPropertyValue()) Version 1.2:
      Fixed: The drive exists & drive type check only worked locally when a drive was specified in $sDrive
    • colombeen
      By colombeen
      Hi guys,
      I'm trying to get some information using WMI, from the Win32_EncryptableVolume class.
      I exec my query, filter out the C-drive, but when I need more info using the objects methods, I only get 1 value back and I can't seem to retrieve the other out params that should be there.
      A very minimal version of what I'm trying to do (no error checking etc, very basic). You need to start SciTE as admin or you won't see any results in the console!
      #RequireAdmin $strComputer = @ComputerName $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\CIMV2\Security\MicrosoftVolumeEncryption") $objWMIQuery = $objWMIService.ExecQuery("SELECT * FROM Win32_EncryptableVolume WHERE DriveLetter='C:'", "WQL", 0) For $objDrive In $objWMIQuery ConsoleWrite("> " & $objDrive.GetConversionStatus() & @CRLF) ConsoleWrite("> " & $objDrive.GetConversionStatus().ConversionStatus & @CRLF) ConsoleWrite("> " & $objDrive.GetConversionStatus().EncryptionPercentage & @CRLF) Next The result from the console is : 
      > 0 > > What I'm expecting to get back is : 
      > 0 > 0 > 0 When using powershell I get this (run as admin is required!!!) : 
      PS C:\WINDOWS\system32> (Get-WmiObject -namespace "Root\cimv2\security\MicrosoftVolumeEncryption" -ClassName "Win32_Encryptablevolume" -Filter "DriveLetter='C:'").GetConversionStatus() ... ConversionStatus : 0 EncryptionFlags : 0 EncryptionPercentage : 0 ReturnValue : 0 ... All I seem to be getting is the ReturnValue when I use the method.
      I've tried this on multiple methods, always ending up with the same result
      Anyone here who has experience with this type of thing?
       
      Greetz
      colombeen
    • 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.
    • 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?
       
×