antmar904 Posted November 22, 2017 Share Posted November 22, 2017 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 More sharing options...
Moderators JLogan3o13 Posted November 22, 2017 Moderators Share Posted November 22, 2017 @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 More sharing options...
Earthshine Posted November 22, 2017 Share Posted November 22, 2017 (edited) 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 November 22, 2017 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
Earthshine Posted November 22, 2017 Share Posted November 22, 2017 (edited) 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 November 22, 2017 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
antmar904 Posted November 22, 2017 Author Share Posted November 22, 2017 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! Earthshine 1 Link to comment Share on other sites More sharing options...
Earthshine Posted November 22, 2017 Share Posted November 22, 2017 wish i could get that to work. My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
antmar904 Posted November 22, 2017 Author Share Posted November 22, 2017 (edited) 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 November 22, 2017 by antmar904 Earthshine and aa2zz6 2 Link to comment Share on other sites More sharing options...
Earthshine Posted November 22, 2017 Share Posted November 22, 2017 (edited) 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 November 22, 2017 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
antmar904 Posted December 4, 2017 Author Share Posted December 4, 2017 Is there a way to make this faster? I am searching about 155 remote computers and this can take one hour sometimes longer. expandcollapse popup#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 Earthshine 1 Link to comment Share on other sites More sharing options...
Earthshine Posted December 4, 2017 Share Posted December 4, 2017 (edited) 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 December 4, 2017 by Earthshine My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
iamtheky Posted December 4, 2017 Share Posted December 4, 2017 (edited) 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 December 4, 2017 by iamtheky Earthshine 1 ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__) Link to comment Share on other sites More sharing options...
antmar904 Posted December 4, 2017 Author Share Posted December 4, 2017 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: expandcollapse popup#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 More sharing options...
antmar904 Posted December 4, 2017 Author Share Posted December 4, 2017 (edited) 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 December 4, 2017 by antmar904 Link to comment Share on other sites More sharing options...
iamtheky Posted December 4, 2017 Share Posted December 4, 2017 (edited) 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 December 4, 2017 by iamtheky ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__) Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now