Jump to content
antmar904

Search WMIC for installed software

Recommended Posts

antmar904

Hi,

I am trying to query WMIC on a remote computer to see if a particular program is installed (Microsoft .Net 4.6.1).  There are plenty of ways to go about this but I think WMI would be the most reliable way.

I'm having issues with the syntax.  This works from a command prompt: wmic /node:COMPUTERNAME product get name, version|find /i ".Net" but I can't get this into AutoIT.  How would I then see if ".Net" was found.  Should I read the STDOUT or do some type of error leveling?

I've also noticed that I can't send STDOUT stream when using "RunWait" only when using "Run".  Is that correct?

RunWait(@ComSpec & ' /c wmic /node: "' & $ComputerName[$i] & product get name, version|find /i ".Net")

 

Share this post


Link to post
Share on other sites
JLogan3o13

@antmar904 This is what I have used in the past, has always worked well:

Local $sPC, $sAppName, $oWMI, $aSystem

$sPC = "<PC Name>"
$sAppName = "<App Name>"

    If Ping($sPC) Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sPC & "\root\cimv2")
            If IsObj($oWMI) Then
                $aSystem = $oWMI.ExecQuery("Select * from Win32_Product")
                    For $oApp In $aSystem
                        If StringInStr($oApp.Name, $sAppName) Then ConsoleWrite("Application: " & $oApp.Name & " Version: " & $oApp.Version & @CRLF)
                    Next
            Else
                ConsoleWrite("Unable to connect to WMI on " & $sPC & @CRLF)
            EndIf
    Else
        ConsoleWrite("Unable to Ping " & $sPC & @CRLF)
    EndIf

 


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

Share this post


Link to post
Share on other sites
Earthshine
i found this powershell command that will tell you right quick. i can't ever get WMI to work.

https://stackoverflow.com/questions/1565434/how-do-i-find-the-net-version

gci 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -recurse | gp -name Version,Release -EA 0 |
     where { $_.PSChildName -match '^(?!S)\p{L}'} | select PSChildName, Version, Release

PSChildName                    Version                       Release                      
-----------                    -------                       -------                      
v2.0.50727                     2.0.50727.5420                                             
v3.0                           3.0.30729.5420                                             
Windows Communication Found... 3.0.4506.5420                                              
Windows Presentation Founda... 3.0.6920.5011                                              
v3.5                           3.5.30729.5420                                             
Client                         4.7.02053                     460805                       
Full                           4.7.02053                     460805                       
Client                         4.0.0.0   

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Earthshine

WMIC is disabled for security reasons on our machines. sigh.

I have to resort to stuff like this.... log4a and regsearch were written by folks around here. I made a test to check for .Net Framework 4.6.1 like you wanted. sorry, can't help with wmic

log4a.au3

RegSearch.au3

WhatIsInstalled.au3

>Running:(3.3.14.2):C:\Program Files (x86)\AutoIt3\autoit3.exe "C:\Users\root\Desktop\WhatIsInstalled.au3"    
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
11\22\2017 10:20:00 | BUILD1 | Info | HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2F0ECC80-B9E4-4485-8083-CD32F22ABD92}\DisplayName = Microsoft .NET Framework 4.6.1 SDK
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{8BC3EEC9-090F-4C53-A8DA-1BEC913040F9}\DisplayName = Microsoft .NET Framework 4.6.1 Targeting Pack
+>10:20:00 AutoIt3.exe ended.rc:0
+>10:20:00 AutoIt3Wrapper Finished.
>Exit code: 0    Time: 1.08

 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
antmar904
1 hour ago, JLogan3o13 said:

@antmar904 This is what I have used in the past, has always worked well:

Local $sPC, $sAppName, $oWMI, $aSystem

$sPC = "<PC Name>"
$sAppName = "<App Name>"

    If Ping($sPC) Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sPC & "\root\cimv2")
            If IsObj($oWMI) Then
                $aSystem = $oWMI.ExecQuery("Select * from Win32_Product")
                    For $oApp In $aSystem
                        If StringInStr($oApp.Name, $sAppName) Then ConsoleWrite("Application: " & $oApp.Name & " Version: " & $oApp.Version & @CRLF)
                    Next
            Else
                ConsoleWrite("Unable to connect to WMI on " & $sPC & @CRLF)
            EndIf
    Else
        ConsoleWrite("Unable to Ping " & $sPC & @CRLF)
    EndIf

 

Thank you @JLogan3o13 This worked well.

I add a array of remote computer names and I am currently running it.  Seems to be going well.  Thanks again!

  • Like 1

Share this post


Link to post
Share on other sites
Earthshine

wish i could get that to work.


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
antmar904
6 minutes ago, Earthshine said:

wish i could get that to work.

#include <Array.au3>
#include <AutoITConstants.au3>

;From JLogan3o13 @ https://www.autoitscript.com/forum/topic/191287-search-wmic-for-installed-software/

Local $sAppName, $oWMI, $aSystem, $ComputerList = @ScriptDir & "\ComputerNames.txt", $LogFile = @ScriptDir & "\LogFile.txt", $sPC = FileReadToArray($ComputerList)

_ArrayDisplay($sPC) ;Debug

If Not FileExists($ComputerList) Then
    MsgBox(48, "Error", "Missing the computer list file : " & @CRLF & $ComputerList & @CRLF & @CRLF & "Please make sure it exist then run the script again.")
    Exit
EndIf

FileWriteLine($LogFile, @CRLF)
FileWriteLine($LogFile, @MON & "/" & @MDAY & "/" & @YEAR & " - " & @HOUR & ":" & @MIN & ":" & @SEC & " Software Check Started" & @CRLF)

;$sPC = "<Computer Name>"
$sAppName = ".Net"

For $i = 0 To UBound($sPC) - 1
    If Ping($sPC, 2000) Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sPC[$i] & "\root\cimv2")
        If IsObj($oWMI) Then
            $aSystem = $oWMI.ExecQuery("Select * from Win32_Product")
            For $oApp In $aSystem
                ;If StringInStr($oApp.Name, $sAppName) Then ConsoleWrite($sPC[$i] & "Application: " & $oApp.Name & "Version: " & $oApp.Version & @CRLF)
                If StringInStr($oApp.Name, $sAppName) Then FileWriteLine($LogFile, $sPC[$i] & "," & $oApp.Name & "," & $oApp.Version & @CRLF)
            Next
        Else
            ;ConsoleWrite("Unable to connect to WMI on " & $sPC[$i] & @CRLF)
            FileWriteLine($LogFile, $sPC[$i] & "," & "Offline" & @CRLF)
        EndIf
    EndIf
Next

 

Edited by antmar904
  • Like 2

Share this post


Link to post
Share on other sites
Earthshine

our ability run scripts is very limited in my environment it seems. i get nothing, and the powershell script shows everything. so does the registry. I don't know what I am doing wrong. The WMIDiags says everything is fine. thanks for your code, it did create a log file and the output was null. darn it.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
antmar904

Is there a way to make this faster?  I am searching about 155 remote computers and this can take one hour sometimes longer.

#include <Array.au3>
#include <AutoITConstants.au3>
#include <Timers.au3>

;From JLogan3o13 @ https://www.autoitscript.com/forum/topic/191287-search-wmic-for-installed-software/

Local $sAppName, $oWMI, $aSystem, $ComputerList = @ScriptDir & "\ComputerNames.txt", $LogFile = @ScriptDir & "\" & @MON & "" & @MDAY & "" & @YEAR & "_" & @HOUR & "_" & @MIN & "_LogFile.txt", $sPC = FileReadToArray($ComputerList)

_ArrayDisplay($sPC) ;Debug

Local $StartTime = _Timer_Init()

If Not FileExists($ComputerList) Then
    MsgBox(48, "Error", "Missing the computer list file : " & @CRLF & $ComputerList & @CRLF & @CRLF & "Please make sure it exist then run the script again.")
    Exit
EndIf

FileWriteLine($LogFile, @CRLF)
FileWriteLine($LogFile, @MON & "/" & @MDAY & "/" & @YEAR & " - " & @HOUR & ":" & @MIN & ":" & @SEC & " Software Check Started" & @CRLF)

;$sPC = "<Computer Name>"
$sAppName = ".Net"

For $i = 0 To UBound($sPC) - 1
    If Ping($sPC, 250) Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sPC[$i] & "\root\cimv2")
        If IsObj($oWMI) Then
            $aSystem = $oWMI.ExecQuery("Select * from Win32_Product")
            For $oApp In $aSystem
                ;If StringInStr($oApp.Name, $sAppName) Then ConsoleWrite($sPC[$i] & "Application: " & $oApp.Name & "Version: " & $oApp.Version & @CRLF)
                If StringInStr($oApp.Name, $sAppName) Then FileWriteLine($LogFile, $sPC[$i] & "," & $oApp.Name & "," & $oApp.Version & @CRLF)
            Next
        Else
            ;ConsoleWrite("Unable to connect to WMI on " & $sPC[$i] & @CRLF)
            FileWriteLine($LogFile, $sPC[$i] & "," & "Offline" & @CRLF)
        EndIf
    EndIf
Next

FileWriteLine($LogFile, @MON & "/" & @MDAY & "/" & @YEAR & " - " & @HOUR & ":" & @MIN & ":" & @SEC & " Software Check Completed." & @CRLF)

Local $DiffTime = _Timer_Diff($StartTime)
Local $EndTime = $DiffTime / 60000
Local $sTime = StringTrimRight($EndTime, 12)
MsgBox(0, "", "Total Runtime: " & $sTime & " Minute")
Exit

 

  • Like 1

Share this post


Link to post
Share on other sites
Earthshine

well i guess you could do it with powershell, but there are better experts around here for that. still, i hear WMI is one of the best ways to do it around here. nice scripting.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
iamtheky

For every app on every computer you are opening a file, writing a line, and closing the file?  How about write that object to an array or one big ass string, then only once per computer (or with only 155 computers you could probably just concatenate them all) perform a _FileWriteFromArray. 

Try and do as little as possible in the loops, and for sure dont go opening and closing files until necessary.

Also, powershell does the same shit, only slower since you would be asking autoit to ask powershell to ask WMI about the installed software.  Do you have an SCCM, that speeds this up greatly as we could just ask that?

Edited by iamtheky
  • Like 1

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

Share this post


Link to post
Share on other sites
antmar904
2 hours ago, iamtheky said:

For every app on every computer you are opening a file, writing a line, and closing the file?  How about write that object to an array or one big ass string, then only once per computer (or with only 155 computers you could probably just concatenate them all) perform a _FileWriteFromArray. 

Try and do as little as possible in the loops, and for sure dont go opening and closing files until necessary.

Also, powershell does the same shit, only slower since you would be asking autoit to ask powershell to ask WMI about the installed software.  Do you have an SCCM, that speeds this up greatly as we could just ask that?

No SCCM.

I'm testing this out now:

#include <Array.au3>
#include <AutoITConstants.au3>
#include <Timers.au3>
#include <File.au3>

;From JLogan3o13 @ https://www.autoitscript.com/forum/topic/191287-search-wmic-for-installed-software/

Local $sAppName, $oWMI, $aSystem, $ComputerList = @ScriptDir & "\ComputerNames.txt", $LogFile = @ScriptDir & "\" & @MON & "" & @MDAY & "" & @YEAR & "_" & @HOUR & "_" & @MIN & "_LogFile.txt", $sPC = FileReadToArray($ComputerList)

;_ArrayDisplay($sPC, "Computer List") ;Debug

Local $StartTime = _Timer_Init()

If Not FileExists($ComputerList) Then
    MsgBox(48, "Error", "Missing the computer list file : " & @CRLF & $ComputerList & @CRLF & @CRLF & "Please make sure it exist then run the script again.")
    Exit
EndIf

;FileWriteLine($LogFile, @CRLF)
;FileWriteLine($LogFile, @MON & "/" & @MDAY & "/" & @YEAR & " - " & @HOUR & ":" & @MIN & ":" & @SEC & " Software Check Started" & @CRLF)

;$sPC = "<Computer Name>"
$sAppName = ".Net"

Local $Array_Base[2] ;Create Array
Local $Array = $Array_Base

For $i = 0 To UBound($sPC) - 1
    If Ping($sPC, 250) Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $sPC[$i] & "\root\cimv2")
        If IsObj($oWMI) Then
            $aSystem = $oWMI.ExecQuery("Select * from Win32_Product")
            For $oApp In $aSystem
                ;If StringInStr($oApp.Name, $sAppName) Then ConsoleWrite($sPC[$i] & "Application: " & $oApp.Name & "Version: " & $oApp.Version & @CRLF)
                If StringInStr($oApp.Name, $sAppName) Then _ArrayAdd($Array, $sPC[$i] & "," & $oApp.Name & "," & $oApp.Version)
            Next
        Else
            ;ConsoleWrite("Unable to connect to WMI on " & $sPC[$i] & @CRLF)
            _ArrayAdd($Array, $sPC[$i] & "," & "Offline")
        EndIf
    EndIf
Next

;_ArrayDisplay($Array)

;FileWriteLine($LogFile, @MON & "/" & @MDAY & "/" & @YEAR & " - " & @HOUR & ":" & @MIN & ":" & @SEC & " Software Check Completed." & @CRLF)
_FileWriteFromArray($LogFile, $Array)

Local $DiffTime = _Timer_Diff($StartTime)
Local $EndTime = $DiffTime / 60000
Local $sTime = StringTrimRight($EndTime, 12)
MsgBox(0, "", "Total Runtime: " & $sTime & " Minute")

Exit

 

Share this post


Link to post
Share on other sites
antmar904

Just ran it on 143 remote computers and it took 56 minutes using Arrays instead of writing to a log file so I'm getting the same results in performance.

Removing the "ping" function and testing again.

Edited by antmar904

Share this post


Link to post
Share on other sites
iamtheky

try "powershell get-package *" instead of the WMI line.  I dont know that it is ever chosen for speed as powershell is usually slow and safe.

you may want to run it from cmd with /c and @SW_Hide parameter.

***edit:  However, if you have remote powershell enabled then you may get away with a single startup and piping all those IPs through that single instance.  Dont wait up for me, I found a rabbit hole I will be down in.

Edited by iamtheky

,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-.
|(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/
(_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_)
| | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) (
| | | | |)| | \ / | | | | | |)| | `--. | |) \ | |
`-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_|
'-' '-' (__) (__) (_) (__)

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

×