使用 msiexec 卸载应用程序时是否有 GUID 的替代方法?
Is there an alternative to GUID when using msiexec to uninstall an application?
当 运行 我们的卸载脚本包含 msiexec 时,我们目前正在使用 GUID 来识别应用程序。我遇到的问题是每次安装最新版本的应用程序时 GUID 都会更改,所以我想知道是否有其他方法可以使用 msiexec 识别我们的应用程序 运行?
首先:产品 GUID 随应用程序的新版本发生变化是正常的,但也可以在不更改产品 GUID 的情况下升级某些应用程序(参考为 minor upgrades - as opposed to major upgrades,即更改产品 GUID)。在同一产品的不同版本之间往往保持稳定的是 UpgradeCode(它定义了一系列相关产品)。 ProductCode 唯一标识产品(在特定版本中)。
此处列出了一些卸载选项:Uninstalling an MSI file from the command line without using msiexec。
我想您可以使用 section 3
中所示的 MSI 文件名,或者如果产品名称保持稳定,您可以将其与自动化一起使用以查找正确的产品 GUID 以卸载有问题的产品.我稍后会测试这个并更新答案。
UPDATE:"product name" 卸载产品的示例 VBScript(假设它在各个版本中保持不变,通常情况下是这样,但不能保证 - 这取决于在产品上)。
在 Add/Remove 程序中找到产品名称 - 或使用链接到此答案底部的微型 VBScript 导出一个包含所有已安装软件包信息的小文本文件。
' On Error Resume Next ' Used to suppress errors
Const msiUILevelNone = 2
Const msiUILevelFull = 5
Const msiInstallStateAbsent = 2
Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
installer.UILevel = msiUILevelFull ' Running with full GUI (if available in MSI)
' installer.UILevel = msiUILevelNone ' Will run uninstall silently, run script with admin rights
' Get the product name from the user
productname = InputBox("Please enter the product name for the MSI package you wish to uninstall:")
If productname = vbCancel Or Trim(productname) = "" Then
WScript.Quit(0)
End If
' Iterate over all MSI packages on the box
For Each product In products
currentproduct = product.InstallProperty("ProductName")
If LCase(currentproduct) = LCase(productname) Then
installer.ConfigureProduct product.productcode, 0, 2 ' msiInstallStateAbsent
MsgBox "Ran uninstall for: " & currentproduct
Exit For ' End product iteration, assuming only one product needed uninstall
End If
Next
Set installer = Nothing
MsgBox "Finished."
更新:您可以使用 VBScript 自己创建一个产品代码和产品名称的快速列表,如本答案底部所述:。我认为这个特定的 VBScript 非常简单。
在这种情况下,人们绕过各种 ProductCode 值的通常方法是从更恒定的 UpgradeCode 开始。
鉴于 UpgradeCode,您可以使用 MsiEnumRelatedProducts(或脚本或 MSI 互操作等效项)来 returnProductCode。像这样的代码通常永远不需要更改。
我很确定 PowerShell 应该能够做到这一点。
您知道哪些内容不会改变,或者确实会改变但您可以轻松跟踪?
说产品代码变了,升级代码没变。您可以按照 PhilDW 的建议使用 MsiEnumRelatedProducts or Installer.Related 或等价物从该升级代码中检索产品代码。
说名字不一样了。您可以按照 Stein 的建议按产品名称查找产品代码,以 MsiEnumProductsEx or Installer.ProductsEx 或等同物开头。
假设您将安装 .msi 的本地副本缓存在一个不变的位置,或者您的脚本很容易找到的副本。您可以按照 4c74356b41 的建议在 msiexec 的命令行中使用该路径。 (请注意 msiexec /x 接受包路径或产品代码。)
假设您不喜欢这些选项中的任何一个。也许您可以在 HKEY_LOCAL_MACHINE\Software\YourCompany\YourProduct 中添加注册表值,将字符串值 ProductCode 设置为 [ProductCode]
。然后您可以使用 reg query HKLM\Software\YourCompany\YourProduct /v ProductCode
或等价物(抱歉,我是 PowerShell 的笨蛋)来获取当前产品代码。 (当然,至少如果您考虑 32 位路径与 64 位路径。)
当 运行 我们的卸载脚本包含 msiexec 时,我们目前正在使用 GUID 来识别应用程序。我遇到的问题是每次安装最新版本的应用程序时 GUID 都会更改,所以我想知道是否有其他方法可以使用 msiexec 识别我们的应用程序 运行?
首先:产品 GUID 随应用程序的新版本发生变化是正常的,但也可以在不更改产品 GUID 的情况下升级某些应用程序(参考为 minor upgrades - as opposed to major upgrades,即更改产品 GUID)。在同一产品的不同版本之间往往保持稳定的是 UpgradeCode(它定义了一系列相关产品)。 ProductCode 唯一标识产品(在特定版本中)。
此处列出了一些卸载选项:Uninstalling an MSI file from the command line without using msiexec。
我想您可以使用 section 3
中所示的 MSI 文件名,或者如果产品名称保持稳定,您可以将其与自动化一起使用以查找正确的产品 GUID 以卸载有问题的产品.我稍后会测试这个并更新答案。
UPDATE:"product name" 卸载产品的示例 VBScript(假设它在各个版本中保持不变,通常情况下是这样,但不能保证 - 这取决于在产品上)。
在 Add/Remove 程序中找到产品名称 - 或使用链接到此答案底部的微型 VBScript 导出一个包含所有已安装软件包信息的小文本文件。
' On Error Resume Next ' Used to suppress errors
Const msiUILevelNone = 2
Const msiUILevelFull = 5
Const msiInstallStateAbsent = 2
Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
installer.UILevel = msiUILevelFull ' Running with full GUI (if available in MSI)
' installer.UILevel = msiUILevelNone ' Will run uninstall silently, run script with admin rights
' Get the product name from the user
productname = InputBox("Please enter the product name for the MSI package you wish to uninstall:")
If productname = vbCancel Or Trim(productname) = "" Then
WScript.Quit(0)
End If
' Iterate over all MSI packages on the box
For Each product In products
currentproduct = product.InstallProperty("ProductName")
If LCase(currentproduct) = LCase(productname) Then
installer.ConfigureProduct product.productcode, 0, 2 ' msiInstallStateAbsent
MsgBox "Ran uninstall for: " & currentproduct
Exit For ' End product iteration, assuming only one product needed uninstall
End If
Next
Set installer = Nothing
MsgBox "Finished."
更新:您可以使用 VBScript 自己创建一个产品代码和产品名称的快速列表,如本答案底部所述:
在这种情况下,人们绕过各种 ProductCode 值的通常方法是从更恒定的 UpgradeCode 开始。
鉴于 UpgradeCode,您可以使用 MsiEnumRelatedProducts(或脚本或 MSI 互操作等效项)来 returnProductCode。像这样的代码通常永远不需要更改。
我很确定 PowerShell 应该能够做到这一点。
您知道哪些内容不会改变,或者确实会改变但您可以轻松跟踪?
说产品代码变了,升级代码没变。您可以按照 PhilDW 的建议使用 MsiEnumRelatedProducts or Installer.Related 或等价物从该升级代码中检索产品代码。
说名字不一样了。您可以按照 Stein 的建议按产品名称查找产品代码,以 MsiEnumProductsEx or Installer.ProductsEx 或等同物开头。
假设您将安装 .msi 的本地副本缓存在一个不变的位置,或者您的脚本很容易找到的副本。您可以按照 4c74356b41 的建议在 msiexec 的命令行中使用该路径。 (请注意 msiexec /x 接受包路径或产品代码。)
假设您不喜欢这些选项中的任何一个。也许您可以在 HKEY_LOCAL_MACHINE\Software\YourCompany\YourProduct 中添加注册表值,将字符串值 ProductCode 设置为
[ProductCode]
。然后您可以使用reg query HKLM\Software\YourCompany\YourProduct /v ProductCode
或等价物(抱歉,我是 PowerShell 的笨蛋)来获取当前产品代码。 (当然,至少如果您考虑 32 位路径与 64 位路径。)