Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the MSI product version number using PowerShell?

Our end deliverable has lot of MSI files.

I would ensure whether they has correct product name and product version.

I am using Orca and doing it manually.

How to do it using PowerShell?

like image 794
Samselvaprabu Avatar asked Jan 05 '12 13:01

Samselvaprabu


People also ask

What is MSI product code?

The package code is a GUID identifying a particular Windows Installer package. The package code associates an . msi file with an application or product and can also be used for the verification of sources. The product and package codes are not interchangeable.

What is an MSI version?

Click-to-Run is the technology used to install Microsoft 365 subscription and most versions of Office 2013 and newer. Windows Installer technology (MSI) was used to install the volume license editions of older versions of Office 2016 and older, such as Microsoft Office Professional Plus and Microsoft Office Standard.


2 Answers

This should have been an easy answer... To start with Windows Installer has a COM object you can use:

ProgID: WindowsInstaller.Installer

However when you create an object out of with PowerShell you don't get any of the properties or methods:

$object = New-Object -Com WindowsInstaller.Installer
$object | gm

...Nothing :-(

Apparently this is a problem with PowerShell and its type adapting system. See this blog post for a work around.

http://www.snowland.se/2010/02/21/read-msi-information-with-powershell/

If you use VBScript you shouldn't have this problem.

EDIT:

Here's some VBScript that will get the version I found:

Const msiOpenDatabaseModeReadOnly = 0
Dim msi, db, view

Set msi = CreateObject("WindowsInstaller.Installer")
Set db = msi.OpenDataBase("C:\Users\andy\Desktop\Module.msi", msiOpenDatabaseModeReadOnly)
Set view = db.OpenView("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductVersion'")
Call view.Execute()

GetVersion = view.Fetch().StringData(1)
Wscript.Echo GetVersion

You can call this from PowerShell:

$version = & cscript.exe /nologo GetVersion.vbs

Update! This type adaption problem was frustrating me and I wasn't happy with the VBS solution. After a bit of research I found a way to do this in PowerShell proper. I adapted code from his blog entry. Enjoy!

function Get-MsiDatabaseVersion {
    param (
        [string] $fn
    )

    try {
        $FullPath = (Resolve-Path $fn).Path
        $windowsInstaller = New-Object -com WindowsInstaller.Installer

        $database = $windowsInstaller.GetType().InvokeMember(
                "OpenDatabase", "InvokeMethod", $Null, 
                $windowsInstaller, @($FullPath, 0)
            )

        $q = "SELECT Value FROM Property WHERE Property = 'ProductVersion'"
        $View = $database.GetType().InvokeMember(
                "OpenView", "InvokeMethod", $Null, $database, ($q)
            )

        $View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)

        $record = $View.GetType().InvokeMember(
                "Fetch", "InvokeMethod", $Null, $View, $Null
            )

        $productVersion = $record.GetType().InvokeMember(
                "StringData", "GetProperty", $Null, $record, 1
            )

        $View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null)

        return $productVersion

    } catch {
        throw "Failed to get MSI file version the error was: {0}." -f $_
    }
}

Get-MsiDatabaseVersion "Installer.msi"
like image 94
Andy Arismendi Avatar answered Sep 17 '22 19:09

Andy Arismendi


(Sorry, don't have rep to just add a comment to the accepted answer)

The answer from @davidmartin was super helpful for me.

Only bit I needed to add was to close the object before returning the version otherwise a handle is kept open on the msi and later access can fail:

$View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null)

return $productVersion
like image 29
sme Avatar answered Sep 21 '22 19:09

sme