Jump to content

Search WMIC for installed software


 Share

Recommended Posts

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")

 

Link to comment
Share on other sites

  • Moderators

@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

 

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

  • 2 weeks later...

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

 

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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

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

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...