Jump to content

Get MSI Product Version and Install if newer


Recommended Posts

Hi,

So I am trying to create a script to run on all computers on the network that will periodically check for a new version of the program installer (MSI) and if it exists it will start the setup which should uninstall / upgrade the existing version.

So far I have is this: 

#include <AutoItConstants.au3>
#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

$user = "DomainAdmin"
$pass = "Password"
$domain = "Domain"
; this below script was taken from one of the forum posts I forgot who's it was but if I run into it again i'll give an honorable mention to the creator of the script
GetMSIDetails()
$sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)") ;here i would like to specify a path rather than for it to get me a dialog box to browse the msi file.

$oInstaller = ObjCreate("WindowsInstaller.Installer") 
$oDB = $oInstaller.OpenDataBase($sMSI, 0)
$oView = $oDB.OpenView("SELECT Property,Value FROM Property")

$oView.Execute()

$oCount = 0


While @error = 0
    $oRecords = $oView.Fetch
    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
    EndIf
 WEnd
; The only thing I want the above to get is Product Name & Product Version. Product name to only match if its our software file name (e.g. MatrixCodebase.msi) and Production Version so that the version is greater than say e.g. 1.0.3.0 so if i place a new file in there and its version is 1.0.4.0 then it will run the rest of the script if not it will exit


Local $DisplayMsgBox = MsgBox ($MB_YESNO, "Release components", "****Some Text***** Do you want to deploy? Press 'Yes' to Continue, Or press 'No' to Exit")
Select
   Case $DisplayMsgBox = 6 ;Yes
      CloseRunningOfficePrograms()
      Sleep (1000)
      ;UninstallMatrixCodeBase()
      Sleep (1000)
      ;InstallMatrixCodeBase()
   Case $DisplayMsgBox = 7 ;No
      Exit
      EndSelect

Func CloseRunningOfficePrograms()
If ProcessExists("WINWORD.EXE") Then ProcessClose ("WINWORD.EXE")
If ProcessExists ("EXCEL.EXE") Then ProcessClose ("EXCEL.EXE")
If ProcessExists ("OUTLOOK.EXE") Then ProcessClose ("OUTLOOK.EXE")
If ProcessExists("VISIO.EXE") Then ProcessClose ("VISIO.EXE")
If ProcessExists ("POWERPNT.EXE") Then ProcessClose ("POWERPNT.EXE") EndIf
EndFunc

Func InstallMatrixCodeBase()
FileCopy("*\*\MatrixCodeBase.msi", "C:\Install")
RunAsWait($user, $domain, $pass, 0,"msiexec /i C:\Install\MatrixCodeBase.msi /passive")
FileDelete("*\*\MatrixCodeBase.msi")
EndFunc

 

Link to comment
Share on other sites

  • Developers
48 minutes ago, AasimPathan said:

So I am trying to create a script to run on all computers on the network that will periodically check for a new version of the program installer (MSI) and if it exists it will start the setup which should uninstall / upgrade the existing version.

So far I have is this: 

Great, so what exactly is the question? :) 

Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

you need to search the 64 bit or 32 bit location as appropriate to your msi installer of course but everthihng is located there

HKLM_SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{GUID of your msi which your msi packagers can give you}

from there you can read registry values such as DisplayVersion, which will give you your complete product version, and from that you can determine whether to install the new one or not.

 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

Here is a function that I use to get MSI installed software.  

#include "Array.au3"

Global $aSoftwareList = _SoftwareList() ;All MSI installed software.
_ArrayDisplay($aSoftwareList)

$aSoftwareList = _SoftwareList("Microsoft Office Professional Plus") ;Search for specific software.
_ArrayDisplay($aSoftwareList)

Func _SoftwareList($sSoftwareName = '') ;Search for MSI/Microsoft installed software using WindowsInstaller.Installer COM object.
    Local $oMyError = ObjEvent("AutoIt.Error", "_ComError") ;COM Error Handler
    #forceref $oMyError
    Local $aSoftwareList[1][3]
    Local $oInstaller = ObjCreate('WindowsInstaller.Installer')
    If Not IsObj($oInstaller) Then Return SetError(1, 0, $aSoftwareList)

    Local $Products = $oInstaller.Products
    For $Product In $Products
        If $sSoftwareName <> '' And Not StringInStr($oInstaller.ProductInfo($Product, 'ProductName'), $sSoftwareName) Then ContinueLoop
        ReDim $aSoftwareList[UBound($aSoftwareList) + 1][3]
        $aSoftwareList[UBound($aSoftwareList) - 1][0] = $oInstaller.ProductInfo($Product, 'ProductName')
        $aSoftwareList[UBound($aSoftwareList) - 1][1] = $oInstaller.ProductInfo($Product, 'VersionString')
        $aSoftwareList[UBound($aSoftwareList) - 1][2] = $oInstaller.ProductInfo($Product, 'InstallLocation')
    Next
    $aSoftwareList[0][0] = UBound($aSoftwareList) - 1
    Return $aSoftwareList
EndFunc   ;==>_SoftwareList

Func _ComError($oMyError) ;COM Error function defined in COM Error Handler used in COM functions.
    MsgBox(16, "AutoItCOM ERROR!", "COM Error Intercepted!" & @CRLF & @CRLF & _
            "err.description is: " & @TAB & $oMyError.description & @CRLF & _
            "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _
            "err.number is: " & @TAB & Hex($oMyError.number, 8) & @CRLF & _
            "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
            "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _
            "err.source is: " & @TAB & $oMyError.source & @CRLF & _
            "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _
            "err.helpcontext is: " & @TAB & $oMyError.helpcontext _
            )
EndFunc   ;==>_ComError

 

Adam

Edited by AdamUL
Link to comment
Share on other sites

13 hours ago, Earthshine said:

you need to search the 64 bit or 32 bit location as appropriate to your msi installer of course but everthihng is located there

HKLM_SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{GUID of your msi which your msi packagers can give you}

from there you can read registry values such as DisplayVersion, which will give you your complete product version, and from that you can determine whether to install the new one or not.

 

What if my MSI does not have an uninstaller information? i've looked in the registry file and couldn't find the GUID of the program we install.

15 hours ago, Jos said:

Great, so what exactly is the question? :) 

Jos

The script is half baked right now. doesn't do all of the things i want it to do and thats where i am stuck and need help.

11 hours ago, AdamUL said:

Here is a function that I use to get MSI installed software.  

#include "Array.au3"

Global $aSoftwareList = _SoftwareList() ;All MSI installed software.
_ArrayDisplay($aSoftwareList)

$aSoftwareList = _SoftwareList("Microsoft Office Professional Plus") ;Search for specific software.
_ArrayDisplay($aSoftwareList)

Func _SoftwareList($sSoftwareName = '') ;Search for MSI/Microsoft installed software using WindowsInstaller.Installer COM object.
    Local $oMyError = ObjEvent("AutoIt.Error", "_ComError") ;COM Error Handler
    #forceref $oMyError
    Local $aSoftwareList[1][3]
    Local $oInstaller = ObjCreate('WindowsInstaller.Installer')
    If Not IsObj($oInstaller) Then Return SetError(1, 0, $aSoftwareList)

    Local $Products = $oInstaller.Products
    For $Product In $Products
        If $sSoftwareName <> '' And Not StringInStr($oInstaller.ProductInfo($Product, 'ProductName'), $sSoftwareName) Then ContinueLoop
        ReDim $aSoftwareList[UBound($aSoftwareList) + 1][3]
        $aSoftwareList[UBound($aSoftwareList) - 1][0] = $oInstaller.ProductInfo($Product, 'ProductName')
        $aSoftwareList[UBound($aSoftwareList) - 1][1] = $oInstaller.ProductInfo($Product, 'VersionString')
        $aSoftwareList[UBound($aSoftwareList) - 1][2] = $oInstaller.ProductInfo($Product, 'InstallLocation')
    Next
    $aSoftwareList[0][0] = UBound($aSoftwareList) - 1
    Return $aSoftwareList
EndFunc   ;==>_SoftwareList

Func _ComError($oMyError) ;COM Error function defined in COM Error Handler used in COM functions.
    MsgBox(16, "AutoItCOM ERROR!", "COM Error Intercepted!" & @CRLF & @CRLF & _
            "err.description is: " & @TAB & $oMyError.description & @CRLF & _
            "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _
            "err.number is: " & @TAB & Hex($oMyError.number, 8) & @CRLF & _
            "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
            "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _
            "err.source is: " & @TAB & $oMyError.source & @CRLF & _
            "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _
            "err.helpcontext is: " & @TAB & $oMyError.helpcontext _
            )
EndFunc   ;==>_ComError

 

Adam

That is a great option, but I am not sure how I can use this reason being. We deploy every few weeks and it would seem like all the script does is gets the version of the package installed. How do I get it to see if the version for ex. is newer than 1.0.1.0 then run the install option if its older or equals to 1.0.1.0 it should do nothing.

 

 

Link to comment
Share on other sites

52 minutes ago, AasimPathan said:

What if my MSI does not have an uninstaller information? i've looked in the registry file and couldn't find the GUID of the program we install.

The script is half baked right now. doesn't do all of the things i want it to do and thats where i am stuck and need help.

That is a great option, but I am not sure how I can use this reason being. We deploy every few weeks and it would seem like all the script does is gets the version of the package installed. How do I get it to see if the version for ex. is newer than 1.0.1.0 then run the install option if its older or equals to 1.0.1.0 it should do nothing.

 

 

I am not sure how much this helps if at all, however you could try this:
 

 

#include <AutoItConstants.au3>
#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

$user = "DomainAdmin"
$pass = "Password"
$domain = "Domain"
; this below script was taken from one of the forum posts I forgot who's it was but if I run into it again i'll give an honorable mention to the creator of the script ---------------------------------- LINK TO POST ------------------>>>>>>>>>>https://www.autoitscript.com/forum/topic/166521-read-msi-data-programatically-with-autoit/

;.msiGetMSIDetails()

If FileExists("C:\Program Files\MatrixCodebase\MatrixCodebase.msi") Then
    $sMSI = "C:\Program Files\MatrixCodebase\MatrixCodebase.msi"
ElseIf FileExists("C:\Program Files (x86)\MatrixCodebase\MatrixCodebase.msi") Then    ;here i would like to specify a path rather than for it to get me a dialog box to browse the msi file.
    $sMSI = "C:\Program Files (x86)\MatrixCodebase\MatrixCodebase.msi"
EndIf

$oInstaller = ObjCreate("WindowsInstaller.Installer")
$oDB = $oInstaller.OpenDataBase($sMSI, 0)
$oView = $oDB.OpenView("SELECT Property,Value FROM Property")

$oView.Execute()

$oCount = 0
$pName = ""
$pVer = 0


While @error = 0
    $oRecords = $oView.Fetch
    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
        If $oPropName = "ProductName" Then
            $pName = $oPropValue
        EndIf
        If $oPropName = "ProductVersion" Then
            $pVer = $oPropValue
        EndIf
        If $pName <> "" And $pVer <> 0 Then
            $oPropName = ""

            If $pName = "MatrixCodebase.msi" And $pVer <> FileReadLine(FileOpen("\\NetworkServer\MatrixCodebase\Ver.txt"), 1) Then
                CloseRunningOfficePrograms()
                InstallMatrixCodeBase()
            EndIf
        EndIf
    EndIf
WEnd
; The only thing I want the above to get is Product Name & Product Version. Product name to only match if its our software file name (e.g. MatrixCodebase.msi) and Production Version so that the version is greater than say e.g. 1.0.3.0 so if i place a new file in there and its version is 1.0.4.0 then it will run the rest of the script if not it will exit

Func DeployNewVer()
    Local $DisplayMsgBox = MsgBox($MB_YESNO, "Release components", "****Some Text***** Do you want to deploy? Press 'Yes' to Continue, Or press 'No' to Exit")
    Select
        Case $DisplayMsgBox = 6 ;Yes
            CloseRunningOfficePrograms()
            Sleep(1000)
            ;UninstallMatrixCodeBase()
            Sleep(1000)
            ;InstallMatrixCodeBase()
        Case $DisplayMsgBox = 7 ;No
            Exit
    EndSelect
EndFunc   ;==>DeployNewVer

Func CloseRunningOfficePrograms()
    If ProcessExists("WINWORD.EXE") Then ProcessClose("WINWORD.EXE")
    If ProcessExists("EXCEL.EXE") Then ProcessClose("EXCEL.EXE")
    If ProcessExists("OUTLOOK.EXE") Then ProcessClose("OUTLOOK.EXE")
    If ProcessExists("VISIO.EXE") Then ProcessClose("VISIO.EXE")
    If ProcessExists("POWERPNT.EXE") Then ProcessClose("POWERPNT.EXE")
EndFunc   ;==>CloseRunningOfficePrograms

Func InstallMatrixCodeBase()
    FileCopy("*\*\MatrixCodeBase.msi", "C:\Install")
    RunAsWait($user, $domain, $pass, 0, "msiexec /i C:\Install\MatrixCodeBase.msi /passive")
    FileDelete("*\*\MatrixCodeBase.msi")
EndFunc   ;==>InstallMatrixCodeBase

 

Link to comment
Share on other sites

It's 32bit application.

Maybe i am not being clear, the simplest option would be to just do this.

If the shared folder path contains an *.msi file which is newer than a particular date then install the software, else exit

Or

If the shared folder path contains an *.msi file which is newer than a particular version then install the software. But when I use FileGetVersion  on the MSI installer it gives me 0.0.0.0 which is sad as it would be much easier to do it this way i think.

 

What do you think?

 

Link to comment
Share on other sites

4 minutes ago, AasimPathan said:

It's 32bit application.

Maybe i am not being clear, the simplest option would be to just do this.

If the shared folder path contains an *.msi file which is newer than a particular date then install the software, else exit

Or

If the shared folder path contains an *.msi file which is newer than a particular version then install the software. But when I use FileGetVersion  on the MSI installer it gives me 0.0.0.0 which is sad as it would be much easier to do it this way i think.

 

What do you think?

 

stick the part in the while loop that grabs file properties into a func, and make sure to include the part that I modified in the while loop into a function call it on the shared file path version, and the local version, and compare the two (make sure to dump the returned values ver and name to different variables for local vs shared... after that compare if comparison is first then close everything and install new, else do whatever... (you can modify to allow you to input into the function which file property you want...

Edited by rm4453
Link to comment
Share on other sites

12 minutes ago, rm4453 said:

stick the part that i modified in the while loop into a function call it on the shared file path version, and the local version, and compare the two (make sure to dump the returned values ver and name to different variables for local vs shared... after that compare if comparison is first then close everything and install new, else do whatever... (you can modify to allow you to input into the function which file property you want...

Your script is giving me an error.

>"C:\Program Files (x86)\AutoIt3\SciTE\..\autoit3.exe" /ErrorStdOut "C:\Users\username\Desktop\MSIGetVer.au3"    
UpgradeCode = {050884C0-CB1A-46D5-8CCD-B35574D6F79C}
ALLUSERS = 1
Manufacturer = Comapny Name
ProductCode = {8B3DFDFF-D894-4A31-AA92-824729385F15}
ProductLanguage = 1033
ProductName = Matrix Code Base
ProductVersion = 1.0.3.0
SecureCustomProperties = WIX_DOWNGRADE_DETECTED;WIX_UPGRADE_DETECTED
"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
>Exit code: 1    Time: 0.3434
 

Link to comment
Share on other sites

Just now, AasimPathan said:

Your script is giving me an error.

>"C:\Program Files (x86)\AutoIt3\SciTE\..\autoit3.exe" /ErrorStdOut "C:\Users\username\Desktop\MSIGetVer.au3"    
UpgradeCode = {050884C0-CB1A-46D5-8CCD-B35574D6F79C}
ALLUSERS = 1
Manufacturer = Comapny Name
ProductCode = {8B3DFDFF-D894-4A31-AA92-824729385F15}
ProductLanguage = 1033
ProductName = Matrix Code Base
ProductVersion = 1.0.3.0
SecureCustomProperties = WIX_DOWNGRADE_DETECTED;WIX_UPGRADE_DETECTED
"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
>Exit code: 1    Time: 0.3434
 

See ProductName & ProductVersion you want to grab those and since it grabs other things after that just stop grabbing once you have those, that will prevent the error.

Link to comment
Share on other sites

Sorry what? i don't understand it at all

What do i change?

While @error = 0
    $oRecords = $oView.Fetch
    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
        If $oPropName = "ProductName" Then
            $pName = $oPropValue
        EndIf
        If $oPropName = "ProductVersion" Then
            $pVer = $oPropValue
        EndIf
        If $pName <> "" And $pVer <> 0 Then
            $oPropName = ""

            If $pName = "MatrixCodebase.msi" And $pVer <> FileReadLine(FileOpen("A:\U_A\U_W\C_NonFiledFiles\GetOfficePBVersion.txt"), 1) Then
                CloseRunningOfficePrograms()
                InstallMatrixCodeBase()
            EndIf
        EndIf
    EndIf
WEnd

 

Link to comment
Share on other sites

Just now, AasimPathan said:

Sorry what? i don't understand it at all

What do i change?

While @error = 0
    $oRecords = $oView.Fetch
    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
        If $oPropName = "ProductName" Then
            $pName = $oPropValue
        EndIf
        If $oPropName = "ProductVersion" Then
            $pVer = $oPropValue
        EndIf
        If $pName <> "" And $pVer <> 0 Then
            $oPropName = ""

            If $pName = "MatrixCodebase.msi" And $pVer <> FileReadLine(FileOpen("A:\U_A\U_W\C_NonFiledFiles\GetOfficePBVersion.txt"), 1) Then
                CloseRunningOfficePrograms()
                InstallMatrixCodeBase()
                ;ExitLoop ; this would probably work
                ;@error = true ; this would probably work as well (both assume you get to this point in the script)
            EndIf
        EndIf
    EndIf
WEnd

 

3

 

Link to comment
Share on other sites

47 minutes ago, rm4453 said:

See ProductName & ProductVersion you want to grab those and since it grabs other things after that just stop grabbing once you have those, that will prevent the error.

This, What do I do here? what do I modify in the script to ensure that i don't get the error.

"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR

Link to comment
Share on other sites

14 minutes ago, AasimPathan said:

This, What do I do here? what do I modify in the script to ensure that i don't get the error.

"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR

do you get the msgbox when you modify to this:

 

While @error = 0
    $oRecords = $oView.Fetch
    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
        If $oPropName = "ProductName" Then
            $pName = $oPropValue
        EndIf
        If $oPropName = "ProductVersion" Then
            $pVer = $oPropValue
        EndIf
        If $pName <> "" And $pVer <> 0 Then
            $oPropName = ""
            
            MsgBox("", "", "VER = " & FileReadLine(FileOpen("A:\U_A\U_W\C_NonFiledFiles\GetOfficePBVersion.txt"), 1))

            If $pName = "MatrixCodebase.msi" And $pVer <> FileReadLine(FileOpen("A:\U_A\U_W\C_NonFiledFiles\GetOfficePBVersion.txt"), 1) Then
                CloseRunningOfficePrograms()
                InstallMatrixCodeBase()
                ;ExitLoop ; this would probably work
                ;@error = true ; this would probably work as well (both assume you get to this point in the script)
            EndIf
        EndIf
    EndIf
WEnd
; The only thing I want the above to get is Product Name & Product Version. Product name to only match if its our software file name (e.g. MatrixCodebase.msi) and Production Version so that the version is greater than say e.g. 1.0.3.0 so if i place a new file in there and its version is 1.0.4.0 then it will run the rest of the script if not it will exit

 

Link to comment
Share on other sites

Yes i get 2 msg boxes with "VER =" but they both are blank

image.png.f25fa957903f8923b5e276f757633cee.png

 

And i still get this

"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
>Exit code: 1    Time: 21.4

Edited by AasimPathan
Link to comment
Share on other sites

1 minute ago, AasimPathan said:

Yes i get 2 msg boxes with "VER =" but they both are blank

image.png.f25fa957903f8923b5e276f757633cee.png

 

And i still get this

"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
>Exit code: 1    Time: 21.4

looks like you don't have any text in that file we are checking for latest ver

Link to comment
Share on other sites

20 minutes ago, rm4453 said:

looks like you don't have any text in that file we are checking for latest ver

I created the file and entered 1.0.2.2 now i get VER=1.0.2.2 twice

image.png.6ae4a31cd2d66acd2b483b895421c08b.png

Then the error:

"C:\Users\username\Desktop\MSIGetVer.au3" (23) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
>Exit code: 1    Time: 25.45

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...