Get product code installed by Msi

I have a C # program where I need to get the product code of the installed msi. As input, I use only the name msi. Can this be done programmatically?

+6
source share
5 answers

This is the code I used to get UninstallString any MSI.

 private string GetUninstallString(string msiName) { Utility.WriteLog("Entered GetUninstallString(msiName) - Parameters: msiName = " + msiName); string uninstallString = string.Empty; try { string path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products"; RegistryKey key = Registry.LocalMachine.OpenSubKey(path); foreach (string tempKeyName in key.GetSubKeyNames()) { RegistryKey tempKey = key.OpenSubKey(tempKeyName + "\\InstallProperties"); if (tempKey != null) { if (string.Equals(Convert.ToString(tempKey.GetValue("DisplayName")), msiName, StringComparison.CurrentCultureIgnoreCase)) { uninstallString = Convert.ToString(tempKey.GetValue("UninstallString")); uninstallString = uninstallString.Replace("/I", "/X"); uninstallString = uninstallString.Replace("MsiExec.exe", "").Trim(); uninstallString += " /quiet /qn"; break; } } } return uninstallString; } catch (Exception ex) { throw new ApplicationException(ex.Message); } } 

This will produce the following result:

 MsiExec.exe /I{6BB09011-69E1-472F-ACAD-FA0E7DA3E2CE} 

From this line you can take the substring in curly brackets {}, which will be 6BB09011-69E1-472F-ACAD-FA0E7DA3E2CE . Hope this could be the product code.

+4
source

Help answer this question ? They want a product name, but maybe it works for the product code too?

EDIT
If you do not have the MSI file itself to access the database (as indicated in the link above for another question), you can try searching the following registry path for the name of your MSI file:

 HKEY_CLASSES_ROOT\Installer\Products\*\SourceList 

There are many entries in the Products section. Each of these is a product key. Each branch must contain a SourceList node, which in turn must contain a PackageName value. This value contains the MSI file name.

So what I would do:

 for each key in Products { open SourceList subkey read PackageName value if name equals my msi file name { return key-name formatted as GUID } } 
+6
source

The fastest and easiest way is to use WMI with a conditional query string.

  public string GetProductCode(string productName) { string query = string.Format("select * from Win32_Product where Name='{0}'", productName); using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query)) { foreach (ManagementObject product in searcher.Get()) return product["IdentifyingNumber"].ToString(); } return null; } 
+2
source

This code gets the product code directly from the MSI file. Thus, it allows you to read code without installing a file.

 class MsiHandle : SafeHandleMinusOneIsInvalid { public MsiHandle() : base(true) { } protected override bool ReleaseHandle() { return NativeMethods.MsiCloseHandle(handle) == 0; } } class NativeMethods { const string MsiDll = "Msi.dll"; [DllImport(MsiDll, CharSet = CharSet.Unicode, ExactSpelling = true)] public extern static uint MsiOpenPackageW(string szPackagePath, out MsiHandle product); [DllImport(MsiDll, ExactSpelling=true)] public extern static uint MsiCloseHandle(IntPtr hAny); [DllImport(MsiDll, CharSet = CharSet.Unicode, ExactSpelling = true)] static extern uint MsiGetProductPropertyW(MsiHandle hProduct, string szProperty, StringBuilder value, ref int length); [DllImport(MsiDll, ExactSpelling = true)] public static extern int MsiSetInternalUI(int value, IntPtr hwnd); public static uint MsiGetProductProperty(MsiHandle hProduct, string szProperty, out string value) { StringBuilder sb = new StringBuilder(1024); int length = sb.Capacity; uint err; value = null; if(0 == (err = MsiGetProductPropertyW(hProduct, szProperty, sb, ref length))) { sb.Length = length; value = sb.ToString(); return 0; } return err; } } static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static int Main(string[] args) { string msiFile = args[0]; NativeMethods.MsiSetInternalUI(2, IntPtr.Zero); // Hide all UI. Without this you get a MSI dialog MsiHandle msi; uint err; if (0 != (err = NativeMethods.MsiOpenPackageW(args[0], out msi))) { Console.Error.WriteLine("Can't open MSI, error {0}", err); return 1; } // Strings available in all MSIs string productCode; using (msi) { if (0 != NativeMethods.MsiGetProductProperty(msi, "ProductCode", out productCode)) throw new InvalidOperationException("Can't obtain product code"); Console.WriteLine(productCode); return 0; } } } 

Full example in Subversion at http://ankhsvn.open.collab.net/svn/ankhsvn/trunk/src/tools/Ankh.Chocolatey/ Use the username "guest" and password.

+1
source
 private static bool GetUninstallString(string ProductName) { try { RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64); var key = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") ?? localKey.OpenSubKey( @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"); if (key == null) return false; return key.GetSubKeyNames() .Select(keyName => key.OpenSubKey(keyName)) .Select(subkey => subkey.GetValue("DisplayName") as string) .Any(displayName => displayName != null && displayName.Contains(ProductName)); } catch { // Log message return false; } } 

This is very useful for a search string by product name.

0
source

Source: https://habr.com/ru/post/890508/


All Articles