super1337

Read MSI data programatically with AutoIT

11 posts in this topic

There are certain values I would like to get out of an MSI such as Product Name, Publisher, and Version number.

Manually these values can be gathered using ORCA... but is there a way to do it programatically using AutoIT?

Share this post


Link to post
Share on other sites



Try something like this. It returns all properties, but you could easily have it check only for the ones you want:

$sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)")

$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
1 person likes this

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

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Nice stuff... much simplier than I would have guessed.

I made some modifications that might be useful to others for getting a specific MSI Property.

$sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)")

MsgBox(0,0,'ProductName: ' & Execute_MSI_Query($sMSI,'ProductName'))
MsgBox(0,0,'Manufacturer: ' & Execute_MSI_Query($sMSI,'Manufacturer'))
MsgBox(0,0,'ProductVersion: ' & Execute_MSI_Query($sMSI,'ProductVersion'))


Func Execute_MSI_Query($MSIPath, $PropertyName)
    If FileExists($MSIPath) And $PropertyName <> '' Then


        Local $Query = "SELECT Value FROM Property WHERE Property = '" & $PropertyName & "'"

        $oInstaller = ObjCreate("WindowsInstaller.Installer")
        $oDB = $oInstaller.OpenDataBase($MSIPath, 0)
        $oView = $oDB.OpenView($Query)

        $oView.Execute()

        $oRecords = $oView.Fetch
        $oPropValue = $oRecords.StringData(1)

        If $oPropValue <> "" Then
            Return $oPropValue
        EndIf

    EndIf

    Return ""
EndFunc
Edited by super1337

Share this post


Link to post
Share on other sites

#4 ·  Posted

On 1/3/2015 at 2:58 AM, JLogan3o13 said:

Try something like this. It returns all properties, but you could easily have it check only for the ones you want:

$sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)")

$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

I am getting error as below, when I execute this code for last record.

"C:\Users\ukreddy\Desktop\test.au3" (19) : ==> The requested action with this object has failed.:
$oPropValue = $oRecords.StringData(2)
$oPropValue = $oRecords^ ERROR
->14:59:31 AutoIt3.exe ended.rc:1
+>14:59:31 AutoIt3Wrapper Finished.

But the @error is 0 for it.

Share this post


Link to post
Share on other sites

#5 ·  Posted

@ur Is it failing on a particular property? Have you tried it on multiple MSIs to ensure it is not something specific to the Property table of the one file?


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

Share this post


Link to post
Share on other sites

#6 ·  Posted

Yeah @JLogan3o13,

I tried on multiple msi files. It is failing for the last value in the table.

Maybe the @error = 0 is not the valid one to check the end of table.

 

Share this post


Link to post
Share on other sites

#7 ·  Posted

Perhaps not, it has been a long time since I posted that. I will take a look when I get a few moments to see what may have changed.


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

Share this post


Link to post
Share on other sites

#8 ·  Posted

I am looking for a graceful "end of table" marker. But as a workaround you could just check to see if the object exists:

$sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)")

$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
        If Not (IsObj($oRecords)) Then ExitLoop ;<======

    $oPropValue = $oRecords.StringData(2)
    $oPropName = $oRecords.StringData(1)

    If $oPropName <> "" Then
        $oCount += 1
        ConsoleWrite($oPropName & " = " & $oPropValue & @CRLF)
    EndIf
WEnd

 


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

Share this post


Link to post
Share on other sites

#10 ·  Posted

In fact, since I am playing around with it (I had completely forgotten doing this one), I would probably do something like this, rather than a ConsoleWrite. Hindsight :)

#include <Array.au3>

Local $aProperties[1][2] = [["Name", "Value"]]
Local $oRecords, $oPropName, $oPropValue, $iCount = 0
Local $sMSI = FileOpenDialog("MSI Properties", @ScriptDir, "Windows Installer Files (*.msi)")
Local $oInstaller = ObjCreate("WindowsInstaller.Installer")
Local $oDB = $oInstaller.OpenDataBase($sMSI, 0)
Local $oView = $oDB.OpenView("SELECT * FROM Property")

$oView.Execute()

While @error = 0
    $oRecords = $oView.Fetch
        If Not (IsObj($oRecords)) Then ExitLoop

    $oPropName = $oRecords.StringData(1)
    $oPropValue = $oRecords.StringData(2)

    If $oPropName <> "" Then
        $iCount += 1
        _ArrayAdd($aProperties, $oPropName & "|" & $oPropValue)
    EndIf
WEnd

    _ArraySort($aProperties, 0, 1)
    _ArrayDisplay($aProperties)

 

1 person likes this

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

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

 Hi @JLogan3o13

The program is not executing when the below query is executed.

Any idea?

$fname = "Complete"
    Local $oView = $oDB.OpenView("SELECT Component_,Directory FROM FeatureComponents,Component where FeatureComponents.Component_=Component.Component AND Feature_ = '"&$fname&"'")
    $oView.Execute()

 

Edited by ur

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