如何从 msi 包中提取 ProductCode?

Posted

技术标签:

【中文标题】如何从 msi 包中提取 ProductCode?【英文标题】:How to extract ProductCode from msi package? 【发布时间】:2011-06-27 15:54:36 【问题描述】:

我想稍后使用它通过 msiexec 卸载 msi,如 here 所述

【问题讨论】:

这是在 VB 脚本中,但可以提供一些想法:leereid.wordpress.com/2008/08/20/vbscript-get-msi-productcode Orca.exe 是您的朋友,如果您想手动执行此操作 另见***.com/questions/113542/… 【参考方案1】:

我可以想出几十种方法来做到这一点。您目前使用和/或熟悉哪些编程语言?

看看

Execute SQL Statements

您可以使用 WiRunSQL.vbs(在 Platform SDK 中提供)来运行命令:

cscript /nologo WiRunSQL.vbs FOO.msi "SELECT Value FROM Property WHERE Property = 'ProductCode'"

【讨论】:

我想从命令行做。最好的方法是运行一些工具或至少 VB 脚本来完成这项工作。最好使用独立工具。 假设我有 GetProductCode.exe FOO.MSI ...您希望它做什么?设置环境变量?输出到控制台?我正在尝试了解大局,以便提出建议。 我希望它输出到控制台。然后我会保存输出并以这种方式将其传递给 msiexec: cmd /c msiexec /x SOME_PRODUCT_CODE /q 无论如何。我只需要一些简单的方法来获取 ProductCode。 我更新了我的答案以做你想做的事,但我有点困惑,为什么你想得到 PC 和 /x PC,而你可以说 /x FOO.msi Windows Installer XML (WiX) 有一个名为 Deployment Tools Foundation (DTF) 的 MSI SDK。 DTF 包括一个名为 Microsoft.Deployment.WindowsInstaller 的 MSI 互操作库,它是黄金标准。如果您不想要任何依赖项,请查看 P/Invoke.Net 或所述程序集的源代码,了解如何查询 MSI。【参考方案2】:

我编写了一个 Powershell 函数,用于在工作中生成基于 MSI 的 Chocolatey 包,以检测我们的内部包是否正在安装已通过其他方式安装的程序:

function Get-MsiProductCode 
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateScript($_ | Test-Path -PathType Leaf)]
        [string]$Path
    )

    function Get-Property ( $Object, $PropertyName, [object[]]$ArgumentList ) 
        return $Object.GetType().InvokeMember($PropertyName, 'Public, Instance, GetProperty', $null, $Object, $ArgumentList)
    

    function Invoke-Method ( $Object, $MethodName, $ArgumentList ) 
        return $Object.GetType().InvokeMember( $MethodName, 'Public, Instance, InvokeMethod', $null, $Object, $ArgumentList )
    

    $ErrorActionPreference = 'Stop'
    Set-StrictMode -Version Latest

    #http://msdn.microsoft.com/en-us/library/aa369432(v=vs.85).aspx
    $msiOpenDatabaseModeReadOnly = 0
    $Installer = New-Object -ComObject WindowsInstaller.Installer

    $Database = Invoke-Method $Installer OpenDatabase $Path, $msiOpenDatabaseModeReadOnly

    $View = Invoke-Method $Database OpenView "SELECT Value FROM Property WHERE Property='ProductCode'"

    [void]( Invoke-Method $View Execute )

    $Record = Invoke-Method $View Fetch
    if ( $Record ) 
        Get-Property $Record StringData 1
    

    [void]( Invoke-Method $View Close @() )
    Remove-Variable -Name Record, View, Database, Installer

【讨论】:

非常有帮助。谢谢!【参考方案3】:

您可以根据已安装的程序在 PowerShell 中执行以下操作来达到类似的效果:

Get-WmiObject -Class Win32_Product -Filter "Vendor LIKE 'The Company%' AND Name LIKE '%The Product%'" | % 
    Write-Host "Uninstalling $($_.IdentifyingNumber)"
    $_.Uninstall() 

(显然查询越紧,它运行得越快——上面的 LIKE 非常昂贵)

或者你可以在你的堆栈上应用the general technique in here。

【讨论】:

Win32_Product 查询永远不会快速运行,因为坦率地说,MSI WMI 提供程序编写得非常糟糕。这也假设他想要 ProductCode 的 MSI 已安装在系统上。 @ChristopherPainter 够公平的。老实说,我很难回忆起我需要这个和/或我最终实际应用的解决方案:) 另一个警告不要使用Win32_Product,这可能会无意中触发 MSI 修复。

以上是关于如何从 msi 包中提取 ProductCode?的主要内容,如果未能解决你的问题,请参考以下文章

如何按索引从可变参数模板参数包中提取值?

如何从 PyPi 包中提取依赖项

如何从tar.gz包中,提取某些文件?

如何从包含多个 MSI 的 wix 自定义引导程序包中安装/卸载单个 msi,例如安装项目的添加/删除功能?

在 Wix 中获取生成的 ProductCode 作为变量

删除捆绑包中的 MSI 包而不包括源