如何使用PowerShell查找MSI产品版本号?

时间:2021-11-24 07:21:36

Our end deliverable has lot of MSI files.

我们的最终交付品有很多MSI文件。

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

我会确保他们是否有正确的产品名称和产品版本。

I am using Orca and doing it manually.

我正在使用Orca并手动完成。

How to do it using PowerShell?

如何使用PowerShell?

2 个解决方案

#1


24  

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

这应该是一个简单的答案...首先,Windows Installer有一个COM对象,您可以使用:

ProgID: WindowsInstaller.Installer

ProgID:WindowsInstaller.Installer

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

但是,当您使用PowerShell创建对象时,您不会获得任何属性或方法:

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

显然这是PowerShell及其类型适应系统的问题。有关解决方法,请参阅此博客文章。

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

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

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

如果您使用VBScript,则不应该出现此问题。

EDIT:

编辑:

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

这是一些VBScript,它将获得我找到的版本:

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:

您可以从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!

更新!这种类型的适应问题令我感到沮丧,我对VBS解决方案不满意。经过一些研究后,我发现了一种在PowerShell中正确执行此操作的方法。我从他的博客条目中修改了代码。请享用!

function Get-MsiDatabaseVersion {
    param (
        [IO.FileInfo] $FilePath
    )

    try {
        $windowsInstaller = New-Object -com WindowsInstaller.Installer

        $database = $windowsInstaller.GetType().InvokeMember(
                "OpenDatabase", "InvokeMethod", $Null, 
                $windowsInstaller, @($FilePath.FullName, 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 "C:\Installer.msi"

#2


2  

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

(对不起,没有代表只是对接受的答案添加评论)

The answer from @davidmartin was super helpful for me.

来自@davidmartin的答案对我来说非常有帮助。

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:

我需要添加的只是在返回版本之前关闭对象,否则在msi上保持句柄打开,以后访问可能会失败:

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

return $productVersion

#1


24  

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

这应该是一个简单的答案...首先,Windows Installer有一个COM对象,您可以使用:

ProgID: WindowsInstaller.Installer

ProgID:WindowsInstaller.Installer

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

但是,当您使用PowerShell创建对象时,您不会获得任何属性或方法:

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

显然这是PowerShell及其类型适应系统的问题。有关解决方法,请参阅此博客文章。

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

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

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

如果您使用VBScript,则不应该出现此问题。

EDIT:

编辑:

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

这是一些VBScript,它将获得我找到的版本:

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:

您可以从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!

更新!这种类型的适应问题令我感到沮丧,我对VBS解决方案不满意。经过一些研究后,我发现了一种在PowerShell中正确执行此操作的方法。我从他的博客条目中修改了代码。请享用!

function Get-MsiDatabaseVersion {
    param (
        [IO.FileInfo] $FilePath
    )

    try {
        $windowsInstaller = New-Object -com WindowsInstaller.Installer

        $database = $windowsInstaller.GetType().InvokeMember(
                "OpenDatabase", "InvokeMethod", $Null, 
                $windowsInstaller, @($FilePath.FullName, 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 "C:\Installer.msi"

#2


2  

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

(对不起,没有代表只是对接受的答案添加评论)

The answer from @davidmartin was super helpful for me.

来自@davidmartin的答案对我来说非常有帮助。

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:

我需要添加的只是在返回版本之前关闭对象,否则在msi上保持句柄打开,以后访问可能会失败:

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

return $productVersion