如何找到已安装的MSI文件的升级代码?

编程入门 行业动态 更新时间:2024-10-26 22:30:14
本文介绍了如何找到已安装的MSI文件的升级代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

在某些情况下,可能会需要检索已部署软件包的MSI升级代码.

In certain cases the need to retrieve MSI upgrade codes for deployed packages can arise.

常见方案:

  • 我接管了其他人的MSI项目,我需要确定已在狂野使用的以前版本使用了哪些升级代码.这是处理升级方案所必需的. 我在任何地方都没有发行版本的存档.
  • 在开发过程中,我不小心多次更改了WiX软件包的升级代码,并且需要狂野地"找到所有升级代码版本. 我不知道各个版本之间的升级代码应该保持稳定.
  • I took over someone else's MSI project, and I need to determine what upgrade codes were used for previous versions that are already in the wild. This is necessary to handle upgrade scenarios. I have no archive of releases anywhere.
  • I accidentally changed the upgrade code for my WiX package several times during development and I need to find all Upgrade Code versions "in the wild". I was not aware that Upgrade Codes should remain stable between versions.

这是一个问/答样式问题.

这个问题曾以各种形式出现过,但这不是重复的.我正在发布一种使用 MSI主自动化界面(或严格来说是WMI)的方法. 应该比以前答案中基于注册表的方法更可靠.该答案还试图总结其他检索方法.

This question has come up before in various incarnations, but this is not a duplicate. I am posting a way to do it that uses the main MSI automation interface (or strictly speaking WMI). It should be more reliable than registry based approaches from previous answers. This answers also tries to summarize other retrieval approaches.

推荐答案

MSI升级代码检索(通过PowerShell/WMI)

正在卸载? : Via Upgrade Code, Via Product Code, Via Product Name, etc...

下面的 PowerShell脚本应检索安装在您的计算机上的所有相关的产品代码,升级代码和产品名称机器(表输出).

The PowerShell script below should retrieve all related product codes, upgrade codes and product names installed on your machine (table output).

输出(以下完整脚本)的屏幕截图:

Screenshot of output (full script below):

这些是直接在相关计算机上的 Windows Installer数据库中的实时值.无需任何转换或解释.我们正在使用正确的API.

These are the real, live values directly from the Windows Installer database on the machine in question. There is no need for any conversion or interpretation. We are going through the proper APIs.

技术注释!:请注意,直接在原始MSI文件(属性表)或WiX源文件中检查属性可能与实际安装的值不匹配,因为可以在安装时通过转换(以下更多信息)-或在命令行中指定的属性值.故事的寓意是:在可能的情况下直接从系统中检索属性值.

Technical note!: Be aware that checking properties directly in your original MSI file (property table) or WiX source file, may not match actual installed values since properties can be overridden at install time via transforms (more info below) - or property values specified at the command line. The moral of the story: retrieve property values directly from the system when you can.

快速免责声明:在极少数情况下,运行脚本可能会触发Windows Installer的自我修复.在免责声明"部分中了解更多信息. 以下.只是潜在的麻烦,但请阅读免责声明.

Quick disclaimer: In rare cases running the script can trigger a Windows Installer self-repair. Read more in "disclaimer section" below. Just a potential nuisance, but read the disclaimer please.

作为题外话,还有一个单行PowerShell命令,该命令将仅检索产品代码和升级代码-不包括程序包名称.对于某些用户,这实际上可能就足够了(不过,我建议使用下面的完整脚本).下面的部分中有此单线输出的屏幕截图. 注意:此命令的显示速度比较大的脚本快得多( )(值"字段是升级代码).另请注意:据我所知,没有关联升级代码的产品代码将不会显示-它们将在较大的脚本中显示:

As a digression, there is also a one-line PowerShell command which will retrieve product codes and upgrade codes only - without the package name included. This might actually suffice for some users (I would recommend the full script below however). There is a screenshot of the output of this one-liner in a section below. Note: this command appears a lot faster than the larger script (the "Value" field is the upgrade code). Also note: product codes without associated upgrade codes will not show up as far as I can tell - they will in the larger script:

gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

要在下面运行完整的PowerShell脚本:

  • 启动PowerShell (按住Windows键,点按R,释放Windows键,键入"powershell",然后按OK或按Enter键.)
  • >
  • 完整复制下面的脚本,然后只需在PowerShell窗口内右键单击.
  • 这应该启动脚本,并且要花相当长的时间才能运行.
  • 请报告任何问题.我不是PowerShell专家-我不是部署专家,也不是编码人员,但是脚本应该可以完成工作.
  • 性能说明:我只获得了整个 Win32_Product WMI对象
    • 樱桃的采摘特性实际上使它变慢了一点(VBScript测试).
    • 我想我们仍然需要获取所有行,而樱桃采摘列只是额外的工作?
    • 对于 Win32_Property ,我们同时过滤行和列(升级代码只是许多行类型之一).为慢速操作做好准备,WMI非常慢.
    • Launch PowerShell (hold down the Windows key, tap R, release the Windows key, type in "powershell" and press OK or hit enter).
    • Copy the script below in its entirety, and then just right click inside the PowerShell window.
    • This should start the script, and it will take quite a while to run.
    • Please report any problems. I am no PowerShell expert - I am a deployment specialist not a coder, but the script should do the job.
    • Performance note: I just get the whole Win32_Product WMI object
      • Cherry picking properties seemed to actually make it marginally slower (VBScript test).
      • I guess we need to get all rows anyway, and cherry picking columns is just extra lifting?
      • For Win32_Property we filter both rows and columns (upgrade code is just one of many row-types). Be prepared for a slow operation, WMI is very slow.
      • $wmipackages = Get-WmiObject -Class win32_product $wmiproperties = gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" $packageinfo = New-Object System.Data.Datatable [void]$packageinfo.Columns.Add("Name") [void]$packageinfo.Columns.Add("ProductCode") [void]$packageinfo.Columns.Add("UpgradeCode") foreach ($package in $wmipackages) { $foundupgradecode = $false # Assume no upgrade code is found foreach ($property in $wmiproperties) { if ($package.IdentifyingNumber -eq $property.ProductCode) { [void]$packageinfo.Rows.Add($package.Name,$package.IdentifyingNumber, $property.Value) $foundupgradecode = $true break } } if(-Not ($foundupgradecode)) { # No upgrade code found, add product code to list [void]$packageinfo.Rows.Add($package.Name,$package.IdentifyingNumber, "") } } $packageinfo | Format-table ProductCode, UpgradeCode, Name # Enable the following line to export to CSV (good for annotation). Set full path in quotes # $packageinfo | Export-Csv "[YourFullWriteablePath]\MsiInfo.csv" # copy this line as well

        在远程计算机上运行

        • 扩展上面的脚本以在远程计算机上运行应该相对容易,但是目前我还没有正确测试它.
        • 下面的信息有点混乱,如果无法理解或不清楚,请告诉我.
        • 在真实Windows域中(理论上)应该只是将远程计算机添加到WMI调用自身中(并遍历计算机列表-请参见下面的模型). . 最重要的是:您应该使用真实的域管理员帐户来运行查询.我不知道,我下面列出的使WMI在工作组环境中工作的更改对于某些域也可能是必需的(防火墙规则和UAC注册表调整).我想一个真正的域管理员帐户应该具有所需的特权和访问权限.
        • WMI中的远程连接受(至少) Windows防火墙, DCOM设置, CIMOM设置和用户帐户的影响控制(UAC)(以及任何其他非Microsoft因素-例如,真实的防火墙,第三方软件防火墙,各种安全软件等).以下是一些详细信息:
          • 设置远程WMI连接
          • 使用PowerShell远程连接到WMI
          • Running on Remote Machines

            • It should be relatively easy to extend the script above to run on remote machines, but I am not set up to test it properly at the moment.
            • The information below has gotten a bit messy, let me know if it is not understandable or unclear.
            • In a real Windows domain it should (in theory) just be a matter of adding the remote machines to the WMI calls themselves (and loop over a list of machines - see mock-up below). And crucially: you should use a real domain admin account to run the query. It is possible that the changes I list below to make WMI work in workgroup environments also could be required for some domains, I don't know (firewall rule and UAC registry tweak). I would guess that a real domain admin account should have the privileges and access required though.
            • Remote connections in WMI are affected by (at least) the Windows Firewall, DCOM settings, CIMOM Settings and User Account Control (UAC) (plus any additional non-Microsoft factors - for instance real firewalls, third party software firewalls, security software of various kinds, etc...). Here are some details:
              • Setting up a Remote WMI Connection
              • Connecting to WMI Remotely with PowerShell
                • 在测试中,我必须( 1 )更新Windows防火墙规则,并( 2 )禁用远程UAC访问令牌筛选和在远程系统上使用真实的本地管理员帐户.请注意,我不建议这些更改中的任何一个,只是报告对我有用的内容.
                • 更改1 :Windows防火墙,运行命令(cmd.exe,以管理员身份运行):netsh advfirewall firewall set rule group="windows management instrumentation (wmi)" new enable=yes( 源 -如果您只是在测试,请参阅此链接以再次禁用此新规则的命令行.本质上只需设置enable = no).请参阅链接的源,以获得可能也适用的限制性更强的规则.
                • 更改2 :禁用远程UAC访问令牌筛选:您需要设置以下注册表值:HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ LocalAccountTokenFilterPolicy = 1( 源 -中页,后半部分).我设置了一个32位DWORD.
                • In my testing I had to (1) update the Windows firewall rules and (2) disable the Remote UAC access token filtering and use a real, local admin account on the remote system. Note that I don't recommend either of these changes, just reporting what worked for me.
                • Change 1: Windows Firewall, run command (cmd.exe, run as admin): netsh advfirewall firewall set rule group="windows management instrumentation (wmi)" new enable=yes (source - see this link for command line to disable this new rule again if you are just testing. Essentially just set enable=no). See the linked source for potentially more restrictive rules that could also work.
                • Change 2: Disable Remote UAC access token filtering: you need to set the following registry value: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ LocalAccountTokenFilterPolicy = 1 (source - mid page, latter half). I set a 32-bit DWORD.

                在远程系统上进行了这些更改之后,我还通过提示用户$Cred = Get-Credential将用户凭据添加到每个呼叫中​​.还有一些用于定义用户凭据的高级选项,如下所述:将密码传递到-凭据(和这里).为了测试运行,这里有一些测试脚本.复制下面的所有行,修改远程计算机名称,然后通过右键单击(将提示您输入凭据)将其粘贴到PowerShell中:

                With those changes in place on the remote system, I also added user credentials to each call by prompting the user $Cred = Get-Credential. There are also more advanced options for defining the user credentials, as explained here: Pass password into -credential (and here). To test run, here is a little test script. Copy all lines below, modify the remote machine name and paste into PowerShell by right clicking (you will be prompted for credentials):

                $Cred = Get-Credential gwmi -ComputerName RemoteMachineName -credential $Cred -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value # copy this line too

                对于上面的大型PowerShell脚本,在 Windows域中的多台计算机上远程运行的基本补充可能是这样的(我不会更新上面的脚本,因为我不能正确测试一下).记住要更新脚本顶部的远程计算机名称列表,并使用域管理员帐户运行:

                For the large PowerShell script above, the basic additions for remote running on several machines in a Windows domain, could be something like this (I won't update the above script since I can't really test this properly). Remember to update the list of remote computer names at the top of the script and run with a domain admin account:

                # DOMAIN NETWORK: mock-up / pseudo snippet ONLY - lacks testing, provided "as is" $ArrComputers = "Computer1", "Computer2", "Computer3" foreach ($Computer in $ArrComputers) { # here we modify the WMI calls to add machine name $wmipackages = Get-WmiObject -Class win32_product -ComputerName $Computer $wmiproperties = gwmi -ComputerName $Computer -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" # the rest of the above, large script here (minus the first 2 WMI lines) }

                要将同一机器循环用于非域网络,可以将凭据添加到WMI调用.这样的事情(系统将提示您输入每台计算机的凭据,这可能会造成混淆).记住要更新脚本顶部的远程计算机名称列表,并在目标框中使用具有本地管理员权限的帐户:

                To adapt the same machine loop for a non-domain network you can add credentials to the WMI calls. Something like this (you will be prompted for credentials for each machine - which might be confusing). Remember to update the list of remote computer names at the top of the script and use an account with local admin rights on the target box:

                # WORKGROUP NETWORK: mock-up / pseudo snippet ONLY - lacks testing, provided "as is" $ArrComputers = "Computer1", "Computer2", "Computer3" foreach ($Computer in $ArrComputers) { $Cred = Get-Credential # here we modify the WMI calls to add machine name AND credentials $wmipackages = Get-WmiObject -Class win32_product -ComputerName $Computer -credential $cred $wmiproperties = gwmi -ComputerName $Computer -credential $cred -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" # the rest of the above, large script here (minus the first 2 WMI lines) }

                真实答案到此为止.我相信上面的较新脚本应能涵盖大多数用例,但由于它不是过时的,因此我也将其内容保留在下面,只是效​​率可能不如上面的脚本.阅读可能会重复.

                The real answer ends here. I believe the above newer script should cover most use-cases, but I will leave the content below as well since it is not obsolete, just probably less efficient than the above script. Reading it will probably be repetitious.

                如果要在运行时从自己的应用程序中检索单个升级代码,则以下用于检索单个升级代码而不是整个列表的脚本可能会很有用.我将保留较旧的内容.

                The scripts below for retrieval of single upgrade codes rather than the whole list, could be of interest if you want to retrieve a single upgrade code from within your own application at run-time. I'll leave that older content in.

                免责声明:以上脚本使用WMI,当您访问类 Win32_Product 时,它将触发 已安装软件包的完整性检查.这很慢,并且可以 非常特殊的情况会触发MSI自我修复.如果你这样不好 参加重要的会议:-).幸运的是您应该能够 取消任何触发的自我修复(但是您的查询可能不会 直到您完成维修为止). 快速上下文链接(用于保管).

                Disclaimer: The above script uses WMI, and when you access the class Win32_Product it triggers an integrity check of installed packages. This is quite slow, and can in very special cases trigger an MSI self-repair. This is not good if you are heading into an important meeting :-). Luckily you should be able to cancel any triggered self-repairs (but your query will probably not complete until you let the repair finish). Quick context link (for safekeeping).

                恕我直言:不要让这阻止您使用WMI-它只是一个 烦恼.注意:下面介绍的PowerShell和VBScript方法都使用WMI,也可以触发此问题.

                IMHO: don't let this stop you from using WMI - it is just an annoyance. Note: both the PowerShell and VBScript approaches described below use WMI and can trigger this issue as well.

                获取未安装的MSI文件的升级代码

                如果您需要在计算机上未安装 的MSI软件包的升级代码,请阅读底部的"手动获取升级代码"部分,几个选项(本质上是在MSI文件本身或用于编译它的源文件中查找).

                Retrieving Upgrade Codes For MSI Files That Are Not Installed

                If you need the upgrade code for an MSI package that is not installed on your machine, please read the "Manual Retrieval of Upgrade Codes" section towards the bottom for several options (essentially look in the MSI file itself, or its source file used to compile it).

                从原始MSI安装文件本身或从用于编译MSI的(WiX)源中获取已安装软件包的升级代码是不安全的,因为升级代码可以是在安装时使用转换 覆盖(以下文本中的详细信息-转换在安装时应用的数据库碎片很少,有关详细信息,请参见Symantec链接.

                It is not safe to get the upgrade code for installed packages from the original MSI install file itself or from the (WiX) sources used to compile the MSI, because upgrade codes can be overridden at install time using transforms (details in text below - transforms are little database fragments applied at install time, see that Symantec link for details).

                以编程方式检索升级代码取决于 WMI ,并且您可以使用 PowerShell 或 VBScript 调用 WMI .两种方法都在下面介绍.本质上,运行以下 WMI查询可以检索指定产品代码的升级代码:

                The programmatic retrieval of upgrade codes relies on WMI, and you can use either PowerShell or VBScript to invoke WMI. Both methods are presented below. Essentially the following WMI query is run to retrieve the upgrade code for a specified product code:

                SELECT * FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='{YourProdGuid}'

                这是用于VBScript和PowerShell的同一查询.您也可以使用WMIExplorer.exe之类的工具将其作为直接WMI查询运行.一个非常有用的工具-强烈推荐.我相信这是他们的网站: github/vinaypamnani/wmie2/releases

                It is the same query used for both VBScript and PowerShell. You can also run it as a straight WMI query using a tool such as as WMIExplorer.exe. A very useful tool - highly recommended. I believe this is their site: github/vinaypamnani/wmie2/releases

                您可以检索指定产品代码的单个升级代码,而不是输出包含所有产品代码和升级代码的整个表格.如果您尝试从自己的应用程序代码内部进行检索,那么这很好(然后,这只是一个标准的WMI查询,与PowerShell无关).

                Rather than outputting a whole table with all product codes and upgrade codes, you can retrieve a single upgrade code for a specified product code. This is good if you are trying to do the retrieval from inside your own application code (then it is just a standard WMI query and has nothing to do with PowerShell).

                以下是通过PowerShell完成的单个升级代码检索(要启动PowerShell:按住Windows键,点击R键,释放Windows键,键入"powershell",然后按OK或按Enter键 ):

                Below is the single upgrade code retrieval done via PowerShell (to launch PowerShell: hold down the Windows key, tap R, release the Windows key, type in "powershell" and press OK or hit enter):

                gwmi -Query "SELECT Value FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='{YourGuid}'" | Format-Table Value

                输出应该是这样的(也许有点难以理解,我应该使用更大的字体):

                The output should be something like this (maybe a little hard to read, I should have used larger fonts):

                在上面的查询中指定的产品代码用于" Windows SDK Intellidocs ".您显然必须用自己的产品代码guid替换它.要查找您需要传递的产品代码,您还可以按照以下说明使用PowerShell查询: 如何找到已安装的MSI安装程序的产品GUID?

                The product code specified in the query above is for "Windows SDK Intellidocs". You must obviously replace it with your own product code guid. To find the product code you need to pass in, you can also use a PowerShell query as described here: How can I find the product GUID of an installed MSI setup?

                返回的升级代码直接来自真实的Windows Installer注册表数据库.它不需要进一步的处理或解释,也不需要手动转换步骤.即使在安装MSI时转换更改了原始升级代码,它也将是正确的(有关以下转换问题的详细信息).

                The returned upgrade code is coming straight from the real Windows Installer registry database. It requires no further processing or interpretation or manual conversion steps. It will also be correct, even if a transform changed the original upgrade code when the MSI was installed (details on transform issues below).

                更新,特别通知:在不必使事情变得不必要的情况下,我相信我在WMI中发现了一个非常具体的错误.如果原始MSI没有设置升级代码,而您通过转换添加了一个代码,则WMI似乎根本不会报告升级代码.但是:如果原始MSI具有升级代码,并且您在转换中覆盖了该代码,则WMI将报告转换的升级代码(这是预期的).我确实看到了这一点,但是需要再使用一个测试包进行验证才能确定. 故事的寓意:请始终在MSI中设置升级代码!然后,您可以永久避免整个问题.并且不要自动生成-对其进行硬编码(请参阅下面的手动获取升级代码"以获取说明).

                Update, special notice: Without complicating things unnecessarily, I believe I have found a bug in WMI that is very specific. When an original MSI has no upgrade code set, and you add one via a transform, then WMI does not seem to report the upgrade code at all. However: if the original MSI has an upgrade code, and you override it in a transform, WMI reports the transform's upgrade code (which is expected). I definitely saw this, but will need to verify with one more test package to be sure. The moral of the story: always set an upgrade code in your MSI! Then you avoid the whole issue permanently. And don't auto-generate it - hard code it (read "Manual Retrieval of Upgrade Codes" below for an explanation).

                下面找到的VBScript解决方案没有任何问题-它甚至比PowerShell更具优势-尽管VBScript到目前为止是一种旧技术.好处是,即使.NET Framework丢失(或锁定),它也可以在所有计算机上运行;而PowerShell(丢失)(或锁定)的机器也可以运行.这是一个过时但可行的解决方案,非常灵活(除非也锁定了VBScript,但是所有现代OS版本都完全支持VBScript).

                There is nothing wrong with the VBScript solution found below - it even has some benefits over PowerShell - despite VBScript being a legacy technology by now. The benefits are that it should work on all machines, even when the .NET framework is missing (or locked), and on machines where PowerShell is missing (or locked). It is a dated, but viable solution that is quite flexible (unless VBScript is also locked, but all modern OS versions fully support VBScript).

                为了尽可能简单地检索升级代码,我创建了一个"裸骨VBScript ",该方法可以解决问题.即使WMI在设计上可以做到这一点,也没有针对远程计算机进行过测试.该脚本旨在在安装了未知升级代码的神秘MSI的系统上运行.

                In order to make it as simple as possible to retrieve your upgrade code, I have created a "bare-bone VBScript" which should do the trick. It has not been tested for targeting remote computers, even if WMI should be able to do so by design. The script is intended to be run on the system where your mystery MSI with the unknown upgrade code is installed.

                此VBScript需要输入产品代码(运行脚本时显示输入对话框),然后它将继续查找相应的升级代码(如果有).如上所述,要查找您的MSI的产品代码,可以使用以下方法: 如何找到已安装的MSI安装程序的产品GUID? .获得产品代码(guid)后,可以在目标计算机上运行此VBScript,并且应在几秒钟内将升级代码返回给您. WMI检索可能非常慢.

                This VBScript requires an input product code (input dialog shown when script is run), and it will then proceed to look up the corresponding upgrade code (if any). As stated above, to locate the product code for your MSI, you can use this approach: How can I find the product GUID of an installed MSI setup?. Once you have the product code (guid), you can run this VBScript on the target machine and you should get the upgrade code returned to you in a few seconds. WMI retrieval can be very slow.

                ' ' Purpose: Barebone / minimal VBScript implementation to allow retrieval of MSI UpgradeCodes via WMI. ' ' Version: 0.2, September.2017 - Stein Åsmul. ' ' Notes: ' ' - As it stands, this script is intended to be run interactively (WScript). ' - Conversion to run via CScript should be trivial (nothing ever is...) ' - The script will ask the user to provide a valid product GUID for an installed MSI. ' - To find a valid product GUID for your system, perhaps see this SO answer: stackoverflow/a/29937569/129130 ' - The script does not RegEx anything to check for valid GUID format (this is barebone - as terse as possible, ' with as little as possible included that can break). ' ' UPDATE: for information on remote running, check "Running on remote machines" section here: ' stackoverflow/a/46637095/129130 (firewall and registry change seems to be needed). strComputer = "." ' Remote connections was NOT tested for this script. In principle you should just add the machine name to "strComputer" above. ' AFAIK you must have "real" admin rights on the box you try to connect to. Many users report intermittent problems running remote WMI. ' Remote connections in WMI are affected by the Windows Firewall, DCOM settings, and User Account Control (UAC). ' - Setting up a Remote WMI Connection: msdn.microsoft/en-us/library/aa822854(v=vs.85).aspx ' - Connecting to WMI on a Remote Computer: msdn.microsoft/en-us/library/aa389290(v=vs.85).aspx ' - Perhaps useful: social.technet.microsoft/Forums/lync/en-US/05205b52-0e43-4ce3-a8b8-58ec4c2edea5/wmi-generic-failure-when-accessing-win32product-remotely?forum=winserverManagement ' - Maybe it is also worth noting that I think WMI queries can be slow enough to trigger timeouts, ' and then you have the old favorite: intermittent bugs. Set owmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") ' User interaction productcode = InputBox("Please paste or type in the product code for the product whose upgrade code you want " + _ "to retrieve (not case sensitive, a blank product code will abort the script)." + vbNewLine + vbNewLine + _ "Please note that the script can take up to a minute to run due to WMI's slowness.", "UpgradeCode retrieval:") If productcode = vbCancel Or Trim(productcode) = "" Then WScript.Quit(0) End If ' Run WMI call and verify that it completes successfully. On Error Resume Next Set upgradecode = owmi.ExecQuery("SELECT Value FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='" & productcode & "'") If (Err.number <> 0) Then MsgBox "The WMI query failed, this is a critical error - aborting.", vbCritical, "Fatal error." WScript.Quit(2) ' Following exit code "standard" from MSI SDK automation samples End If On Error GoTo 0 ' Report results. Select Case upgradecode.count Case 0 ' We have to provide a separate message for this state, since some packages may not have an UpgradeCode. ' However, the product GUID could also have been misspelled. MsgBox "No UpgradeCode was found, are you sure you entered the correct product GUID?" & vbNewLine & vbNewLine & _ "Note: It is possible for a product to NOT have an UpgradeCode.", vbInformation, "No UpgradeCode found." Case 1 ' The "default state" - should cover almost all normal packages. ' Only one upgrade code should have been retrieved, and it can be referenced by upgradecode.ItemIndex(0).Value on newer systems ' (Vista and later), but on XP this apparently does not work (never tested by me), for compatibility we use a standard For Each ' enumeration instead. Source: stackoverflow/questions/2378723/get-first-record-from-wmi-execquery For Each u in upgradecode Msgbox "The Upgrade Code is: " & u.Value & vbNewLine & vbNewLine & _ "Just press CTRL + C to copy all text in this dialog (then paste to notepad or similar to extract the GUID).", _ vbInformation, "UpgradeCode found." ' Exit For Next Case Else ' Should never get here - let us know if you do get this message. MsgBox "An error occurred, the query returned more than one result. There can only be one UpgradeCode. " & _ "Please report this error on StackOverflow", vbInformation, "Error while retrieving UpgradeCode." End Select

                检索计算机上的所有升级代码和产品代码

                我应该提到,我有一个很大的VBScript,它将生成一个 针对所有已安装的MSI软件包的综合HTML报告 在其上运行的计算机.其中包括所有升级代码以及相关列表 产品代码(共享相同升级代码的产品代码).但是,我对代码不太满意(我是部署专家,而不是编码人员).剧本 太大,太慢并且未经测试无法使用,因此我创建了 上面找到的准骨VBScript可以对单个VBScript进行检索 仅包装.该脚本更容易为您测试和修改 自己使用. 如果有兴趣,我可以提供此大型VBScript进行测试.除了将单个HTML文件输出到我的文档"之外,它是只读的.应该可以修改此脚本,以供在远程计算机上使用.

                I should mention that I have a large VBScript which will generate a comprehensive HTML report for all installed MSI packages on the machine it runs on. This includes all upgrade code and a list of related product codes (product codes that share the same upgrade code). However, I am not too happy with the code (I am a deployment specialist, not a coder). The script is too large, too slow and too untested for use, so I create the bare-bone VBScript found above to do retrieval for a single package only. This script is much easier to test and modify for your own use. I can provide this large VBScript for testing if of interest. It is read-only apart from a single HTML file output to "My Documents". It should be possible to adapt this script for use on remote computers as well.

                有一个单行PowerShell命令来检索所有产品代码和相关的升级代码,但是此输出填充缺少产品名称.为了完整起见,我将其包括在这里:

                There is a one-line PowerShell command to retrieve all product codes and related upgrade codes, but this output fill lack the name of the products. I include it here for completeness:

                gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

                输出将与此类似(值"字段是升级代码-据我所知,没有关联升级代码的产品代码将不会显示):

                The output will be similar to this (the "Value" field is the upgrade code - product codes without associated upgrade codes will not show up as far as I can tell):

                本节列出了一些手动方式"来检索不需要任何编码或命令行的升级代码.这些手动方法不是推荐的方法.我之所以将它们包括在内,是因为这试图成为"参考答案".应该提供几个不同的选项. 我的建议是使用上面提供的PowerShell或VBScript.

                This section list some "manual ways" to retrieve upgrade codes that don't need any coding or command lines. These manual approaches are not the recommended ones. I include them only because this attempts to be a "reference answer". Several different options should be provided. My recommendation is to use the PowerShell or VBScript provided above.

                也就是说,升级代码通常不应在产品的各个版本之间发生变化,因此您可以尝试在MSI文件本身或如下所述的用于编译它的源代码中找到的代码.已经多次提到的问题是,转换可以在安装时更改升级代码,因此,如果要确保找到正确的升级代码,则需要以编程方式检索升级代码.除非您尝试从系统上未安装的MSI获取升级代码.然后,您只需要一个MSI文件查看器,如下文要点1所述.

                That being said, upgrade codes should generally never change across versions of your product, so chances are you can try the one you find in the MSI file itself, or in the source used to compile it as described below. The problem that has already been mentioned several times is that a transform can change upgrade codes at install time, so you need to retrieve the upgrade code programatically if you want to be sure you find the correct one. Unless you are trying to get the upgrade code from an MSI that is not installed on your system. Then you just need a MSI file viewer as described below in bullet point 1.

                转换只是一个数据库片段,其更改会在安装时应用于原始MSI.它是主要用于合并应用程序包装的工具,可以在不直接修改MSI文件的情况下修改安装程序.转换的扩展名为.mst.通过转换来更改升级代码是不常见的,但并非闻所未闻-特别是对于公司重新包装而言.在极少数情况下,应用程序打包者可能会故意更改升级指南,以使他们能够将自己的升级交付给已安装的软件包(而不是直接依赖于供应商的更新).很少,但我已经看到了.这是好事还是有争议的.

                A transform is just a database fragment with changes that are applied to the original MSI at install time. It is a tool mostly used for corporate application packaging to modify installers without modifying MSI files directly. Transforms have the extension .mst. Changing the upgrade code via a transform is unusual, but not unheard of - especially for corporate repackaging. In rare cases application packagers may intentionally change the upgrade guid to enable them to deliver their own upgrades to the packages installed (instead of relying on the vendor updates directly). Rare, but I have seen it done. Whether this is a good thing or not is highly debatable.

                轻松,手动方式来查找MSI升级代码:

                Easy, manual ways to find MSI upgrade codes:

              • 尽管很明显,但查找升级代码的最简单方法是打开用于安装产品的原始MSI ,并在属性"表中找到升级代码

                Though offensively obvious, the easiest way to find the upgrade code is to open the original MSI used to install the product and find the upgrade code in the Property table. All you need is a tool capable of opening MSI files. Here are some tools: What installation product to use? InstallShield, WiX, Wise, Advanced Installer, etc. Your fastest bet is probably Orca if you have Visual Studio installed (search for Orca-x86_en-us.msi and install it - this is Microsoft's own, official MSI viewer and editor), or Super Orca if you don't have Visual Studio installed (follow the above link to find it).

                如果您是使用WiX(或任何其他部署工具)的开发人员,则显然可以轻松地在用于编译MSI的WiX源文件中找到升级代码(或Installshield源代码,Advanced Installer源代码或您正在使用的任何部署工具.

                If you are a developer using WiX (or any other deployment tool), you can obviously find the upgrade code easily in your WiX source file that you used to compile your MSI (or Installshield source, Advanced Installer source, or whatever deployment tool you are using).

                • 我们不要在这里提出过多建议,以免使主要问题杂乱无章,但是您显然应该在源代码中硬编码升级代码,并且不要自动生成它!
                • 升级代码定义了"相关产品系列",并且应在各个发行版(版本)中保持稳定.在大多数情况下,它在所有语言版本中也应保持稳定.确切的设置取决于部署要求.
                • 如果产品应该能够并存,那么对于需要共存的产品,通常会有不同的升级代码.
                • 经验法则:尽可能长时间保持升级代码的稳定.在需求绝对需要时进行更改.
                • 总结一下:对于具有自己的"生命周期"并且彼此之间没有真正关系的不同产品,切勿使用相同的升级代码.它们没有关系.这与保持相关产品的升级代码稳定一样重要.考虑"生命周期","家庭关系"和"共存"的要求.
                • 这是一个很大的题外话,回到了当前的问题:查找升级代码.
                • Let's not fly off the handle here with too much well meant advice that clutters the main issue, but you should obviously hard code the upgrade code in your source, and never auto-generate it!
                • Upgrade codes define "families of related products" and should remain stable across releases (versions). In most cases it should remain stable across language versions as well. The exact setup depends on deployment requirements.
                • If products should be able to exist side-by-side you typically have different upgrade codes for the products that need to co-exist.
                • Rule of thumb: keep upgrade codes stable for as long as possible, whenever possible. Change them when requirements absolutely demand it.
                • To wrap things up: never use the same upgrade code for different products that have their own "life cycle" and no real relation to each other. They are not related. This is just as important as keeping your upgrade code stable for related products. Think "life cycle" and "family relation" and "co-existence" requirements.
                • That was a large digression, back to the issue at hand: finding upgrade codes.

                即使您没有原始MSI,也可以从%SystemRoot%\Installer文件夹中的原始安装中找到缓存的MSI .这里的MSI文件带有一个神秘的十六进制名称,但它们只是用于安装不同产品的原始MSI文件的副本-缓存在安全的地方,可用于修改,修复和卸载操作. 无论您做什么,都不要在这个文件夹中四处乱逛.永远不要删除任何东西.您可以通过选择第一个MSI文件并检查Windows资源管理器状态栏,找到旧版本Windows的产品名称,来找到安装产品的MSI.在Windows 10中,看来您可以将鼠标悬停在MSI上,然后弹出带有一些MSI详细信息的弹出窗口.然后,您只需单击列表,直到找到合适的产品,然后打开MSI,并在属性表中找到升级代码.

                Even if you don't have the original MSI, it is even possible to locate the cached MSI from the original install in the %SystemRoot%\Installer folder. The MSI files here have a mysterious hex-name, but they are just copies of the original MSI files used to install the different products - cached in a safe place to be available for modify, repair and uninstall operations. Whatever you do, don't mess around in this folder. Never, ever delete anything. You can find the MSI that installed your product by selecting the first MSI file, and checking the Windows Explorer status bar what the product name is for older Windows version. In Windows 10 it seems you can hover over an MSI with the pointer and you get a pop-up with some MSI details. You then just click through the list until you find the right product and open the MSI and find the upgrade code in the Property table.

                有些人使用注册表读取升级代码:如何在C#中找到已安装应用程序的升级代码?.我认为这不是一个好的方法,有更好的方法-例如仅使用上面解释的PowerShell. 打包的GUID (即Windows Installer注册表数据库中使用的GUID格式.

                Some people use the registry to read the upgrade codes: How can I find the upgrade code for an installed application in C#?. In my opinion this is not a good approach, there are better ways - such as just using PowerShell as explained above. There is no need for all this conversion and interpretation of packed GUIDs (which is the GUID format used in the Windows Installer registry database).

                那应该完成主要的手动方法"以快速获取升级代码.只是一些武器库的方法有时足够好.我可能已经忘记了几种其他方式.

                That should complete the primary "manual methods" to retrieve an upgrade code quickly. Just some methods for the arsenal that are sometimes good enough. There are probably several more ways that I have forgotten.

                不要选择程序化方法,但是如果您急于在没有所有可用工具的情况下工作,则可以使用一些手动选项.但是,其中一些手动方法需要比PowerShell命令行更多的工具(您需要一个MSI文件查看器,如果您正在执行某人计算机的支持任务",则该对话框不一定总是在包装盒上可用).现在是使用PowerShell的时候了(是的,我也觉得过时了.)

                Do prefer the programmatic approaches, but if you are in a rush and working without all your tools available some manual options are good. However some of these manual methods require more tools than the PowerShell command line (you need an MSI file viewer which is not always available on the box if you are on a "support mission" to someone's machine). The time has come to use PowerShell (yes, I feel outdated too).

                顺便说一句,MSI文件实际上是作为存储为COM结构的存储文件(MS Office文件格式)而删除的SQL Server数据库.本质上,文件内的文件系统具有各种类型的存储流.

                Incidentally, MSI files are essentially stripped down SQL Server databases stored as COM-structured storage files (MS Office file format). Essentially a file system within a file with storage streams of various types.

                如果卡在没有MSI查看器的计算机上,则可以直接从PowerShell查询缓存的MSI数据库:

                If you are stuck on a machine without an MSI viewer, you can query cached MSI databases directly from PowerShell:

                • gallery.technet.microsoft/scriptcenter/Get- MsiDatabaseProperties-09d9c87c
                • www.adamtheautomator/powershell-windows-installer -msi-properties/
                • gallery.technet.microsoft/scriptcenter/Get-MsiDatabaseProperties-09d9c87c
                • www.adamtheautomator/powershell-windows-installer-msi-properties/
  • 更多推荐

    如何找到已安装的MSI文件的升级代码?

    本文发布于:2023-11-06 06:13:42,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1562904.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:代码   文件   MSI

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!