Jump to content

Read MSI data programatically with AutoIT


Go to solution Solved by JLogan3o13,

Recommended Posts

Posted

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?

  • Moderators
  • Solution
Posted

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

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

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
  • 2 years later...
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.

  • Moderators
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?

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

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.

 

  • Moderators
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

 

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

  • Moderators
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)

 

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

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

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
  • Recently Browsing   0 members

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