To totally unlock this section you need to Log-in
The product code is the unique GUID of identifying an application or product release; In other words, different versions and languages of Product must have different product codes.
Also, ProductCode can be used to query feature state, and product state. For example, installer API "MsiQueryFeatureStateEx()" and "MsiQueryProductState()", etc.
The following four approaches can give us several methods to find and retrieve (also remotely) the GUID of installed MSI packages:
Use the Powershell "one-liner"
Any self-repair triggered by this option should generally be possible to cancel. The package integrity checks triggered does add some event log "noise" though. Take not that IdentifyingNumber is the ProductCode (WMI peculiarity).
get-wmiobject Win32_Product | Format-Table IdentifyingNumber, Name, LocalPackage -AutoSize
Quick start of Powershell: hold Windows key, tap R, type in "powershell" and press Enter.
Use VBScript
This option may be safer than Powershell for reasons explained in detail below.
In essence it is (much) faster and not capable of triggering MSI self-repair since it does not go through WMI (it accesses the MSI COM API directly - at blistering speed). However, it is more involved than the Powershell option (several lines of code).
You can try a VBScript to access information via the MSI automation interface (core feature of Windows - it is unrelated to WMI).
- Copy the below script and paste into a *.vbs file on your desktop, and try to run it by double clicking. Your desktop must be writable for you, or you can use any other writable location.
- This is a sample VBScript. Terseness has been preferred over error handling and completeness, but it should do the job with minimum complexity.
- The output file is created in the folder where you run the script from (folder must be writable). The output file is called msiinfo.csv.
- Double click the file to open in a spreadsheet application, select comma as delimiter on import - OR - just open the file in Notepad or any text viewer. Opening in a spreadsheet will allow advanced sorting features.
- This script can easily be adapted to show a significant amount of further details about the MSI installation.
'#### Retrieve all ProductCodes (with ProductName and ProductVersion) Set fso = CreateObject("Scripting.FileSystemObject") Set output = fso.CreateTextFile("msiinfo.csv", True, True) Set installer = CreateObject("WindowsInstaller.Installer") On Error Resume Next ' we ignore all errors For Each product In installer.ProductsEx("", "", 7) productcode = product.ProductCode name = product.InstallProperty("ProductName") version=product.InstallProperty("VersionString") output.writeline (productcode & ", " & name & ", " & version) Next output.Close
Registry Lookup
You can also find the product code by perusing the registry from this base key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall.
Press F3 key and search for your product name. If it's a 32-bit installer on a 64-bit machine, it might be under the following key: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall.
The following registry keys are the common locations in which search and find the GUIDs of MSI packages:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
Original MSI File
You can find the Product Code in the Property table of any MSI file (and any other property as well). However, the GUID could conceivably (rarely) be overridden by a transform applied at install time and hence not match the GUID the product is registered under (approach 1 and 2 above will report the real product code - that is registered with Windows - in such rare scenarios).
You need a tool to view MSI files. See towards the bottom of the following answer for a list of free tools you can download (or see quick option below): How can I compare the content of two (or more) MSI files?
For convenience and need for speed, you can download SuperOrca without delay and fuss from this direct-download hotlink - the tool is good enough to get the job done - install, open MSI and go straight to the Property table and find the ProductCode row (please always virus check a direct-download hotlink - obviously - you can use virustotal.com to do so - online scan utilizing dozens of anti-virus and malware suites to scan what you upload).
Another, the original, tool Orca is Microsoft's own tool, it is installed with Visual Studio and the Windows SDK. Try searching for Orca-x86_en-us.msi, under Program Files (x86) and install the MSI if found.
Retrieve Product Codes
Fire up Powershell (hold down the Windows key, tap R, release the Windows key, type in "powershell" and press OK) and run the command below to get a list of installed MSI package product codes along with the local cache package path and the product name (maximize the PowerShell window to avoid truncated names).
Before running this command line, please read the disclaimer below (nothing dangerous, just some potential nuisances). If you are trying to uninstall a package there is a section below with some sample msiexec.exe command lines:
get-wmiobject Win32_Product | Format-Table IdentifyingNumber, Name, LocalPackage -AutoSize
The output should be similar to this:
For some strange reason the "ProductCode" is referred to as "IdentifyingNumber" in WMI. So in other words, in the picture above the IdentifyingNumber is the ProductCode.
Due to strange Microsoft design, any WMI call to Win32_Product (like the PowerShell command below) will trigger a validation of the package estate. Besides being quite slow, this can in rare cases trigger an MSI self-repair. This can be a small package or something huge - like Visual Studio. In most cases this does not happen, but there is a risk.
Don't run this command right before an important meeting, it is not ever dangerous (it is a read-only query), but it might lead to a long repair in very rare cases.
You can also get the output in list form (instead of table):
get-wmiobject -class Win32_Product
In this case the output is similar to this:
Retrieve Product Codes From A Remote Computer
In theory you should just be able to specify a remote computer name as part of the command itself. Here is the same command as above set up to run on the machine "RemoteMachine" (-ComputerName RemoteMachine section added):
get-wmiobject Win32_Product -ComputerName RemoteMachine | Format-Table IdentifyingNumber, Name, LocalPackage -AutoSize
This might work if you are running with domain admin rights on a proper domain. In a workgroup environment (small office / home network), you probably have to add user credentials directly to the WMI calls to make it work.
Additionally, remote connections in WMI are affected by (at least) the Windows Firewall, DCOM settings, and User Account Control (UAC) (plus any additional non-Microsoft factors, for instance additional physical or virtual firewalls, third party software firewalls, security software of various kinds, etc.). Whether it will work or not depends, usually, on your exact setup.
Powershell
PowerShell requires the .NET framework to be installed, but on most modern OSes (Windows Server and Windows platforms, Powershell is already included and available). The actual PowerShell application itself can also be missing from the machine even if .NET is installed. Finally, PowerShell could be disabled or locked by various system policies and privileges.
If this is the case, you can try a few other ways to retrieve product codes. An alternative is VBScript - it is fast and flexible (but can also be locked on certain machines, and scripting is always a little more involved than using tools).
Let's start with a built-in Windows WMI tool, usually used for testing WMI components and functionalities: wbemtest.exe.
- Launch wbemtest.exe (Hold down the Windows key, tap R, release the Windows key, type in "wbemtest.exe" and press OK).
- Click connect and then OK (namespace defaults to root\cimv2), and click "connect" again.
- Click "Query" and type in this WQL command (SQL flavor): SELECT IdentifyingNumber,Name,Version FROM Win32_Product.
- Click "Use" (or equivalent - the tool will be localized).
Sample output screenshot is the following. Not the nicest formatting, but you can get the data you need. IdentifyingNumber is the MSI product code:
Next, you can try a custom, more full featured WMI tool such as WMIExplorer.exe.
- This is not included in Windows. It is a very good tool, however.
- Check it out at: https://github.com/vinaypamnani/wmie2/releases.
- Launch the tool, click Connect, double click ROOT\CIMV2
- From the "Query tab", type in the following query SELECT IdentifyingNumber,Name,Version FROM Win32_Product and press Execute.
Get MSI Packages GUID (Comparing ProductCode and UpgradeCode)
Launch PowerShell: hold down the Windows and R key together, 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.
For Win32_Property we filter both rows and columns (UpgradeCode is just one of many row-types). Be prepared for a slow operation, WMI is very slow doing such retrieves.
$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 #Let's assume that no UpgradeCode is found yet. 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"
The upgrade code is the unique GUID of identifying a family of a product. That is, the same products with different versions have probably been shipped for a few releases. These products have different ProductCodes, but they are linked together by using SAME UpgradeCode.
For example, assuming that we wrote a product called "Happy MSI" and this product only has one MSI package for deployment on client system.
The first release of this product is actually the MSI package with name "version_1.msi", and the second release is "version_2.msi". Then, these two MSI must have same UpgradeCode. When users run "version_2.msi" on their system, the windows installer will use the UpgradeCode to decide if previous versions of this product are already present on the system.
Installer API "MsiEnumRelatedProducts()" uses the UpgradeCode to query all the family products.
Uninstall MSI Packages
If what you want to do is to uninstall the MSI package and you found the product code (GUID) for, you can do this as follows using an elevated command prompt (search for cmd.exe, right click and run as admin):
Option 1: Basic, interactive uninstall without logging (quick and easy):
msiexec.exe /x {00000000-0000-0000-0000-00000000000C}
Quick Parameter Explanation:
- /X = run uninstall sequence
- {00000000-0000-0000-0000-00000000000C} = Product code for product to uninstall
You can also enable (verbose) logging and run in silent mode if you want to, leading us to option 2:
Option 2: silent uninstall with verbose logging (better for batch files):
msiexec.exe /x {00000000-0000-0000-0000-00000000000C} /QN /L*V "C:\My.log" REBOOT=ReallySuppress
Quick Parameter Explanation:
- /X = run uninstall sequence
- {00000000-0000-0000-0000-00000000000C} = Product code for product to uninstall
- /QN = Run completely silently
- /L*V "C:\My.log" = Verbose logging at specified path
- REBOOT=ReallySuppress = Avoid unexpected, sudden reboot