probably at the beach
probably at the beach

Reputation: 15207

Determining the version of an MSI without installing it

I have an MSI file built from my C# Visual Studio 2010. The version is set through the Version property. I wanted to know if there is a way to determine the version without having to install the file. Currently when right click and view the properties it isn't displayed.

Upvotes: 10

Views: 7596

Answers (5)

HackSlash
HackSlash

Reputation: 5803

If you want to quickly pull the version there is a PowerShell module written by a Microsoft employee that does this for you called PSMSI

It's a two step process:

  1. Install the module with: install-package msi -provider PowerShellGet
  2. Get version with: get-msiproperty ProductVersion -Path '.\Installer.msi'

Upvotes: 0

BerndK
BerndK

Reputation: 1080

Based on Gupta's answer, I added COM release calls. If you want to recreate or replace the file you accessed in your further workflow, it might be still in use and you will get an exception if the GC did not yet release the objects, so let's do this manually.

public static string GetMsiInfo(string msiPath, string info)
{
  string retVal = string.Empty;

  Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
  dynamic installer = Activator.CreateInstance(classType);
  try
  {

    // Open msi file
    var db = installer.OpenDatabase(msiPath, 0);
    try
    {
      // Fetch the property
      string sql = $"SELECT Value FROM Property WHERE Property ='{info}'";
      var view = db.OpenView(sql);
      try
      {
        view.Execute(null);

        // Read in the record
        var rec = view.Fetch();
        if (rec != null)
          retVal = rec.StringData(1);

        return retVal;
      }
      finally
      {
        view.Close();
        Marshal.ReleaseComObject(view);
      }
    }
    finally
    {
      //db.Commit();
      Marshal.ReleaseComObject(db);
    }
  }
  finally
  {
    Marshal.ReleaseComObject(installer);
  }
}

I think using this code, there is no need to add a COM reference or an extra namespace as mentioned by Gupta, because we use late binding here (see the dynamic).

Upvotes: 0

Ben Adams
Ben Adams

Reputation: 151

Instead of using the COM library, you can use the Microsoft.Deployment.WindowsInstaller library from the wixtoolset SDK. Once referenced, you can very similarly get the version info.

private string GetMsiInfo(string msiPath)
{
    using (var database = new Microsoft.Deployment.WindowsInstaller.Database(msiPath))
    {
        var sql = "SELECT Value FROM Property WHERE Property ='ProductVersion'";
        using (var view = database.OpenView(sql))
        {
            view.Execute();

            using (var record = view.Fetch())
            {
                var version = record?.GetString(1);
                return version;
            }
        }
    }
}

I haven't found a way to get the correct assembly via nuget installer. However, after I installed the wixtoolset https://wixtoolset.org/releases/, I was able to add a reference in my project directly under assemblies -> extensions -> Microsoft.Deployment.WindowsInstaller.

Upvotes: 0

TonySalimi
TonySalimi

Reputation: 8427

The following code may be helpful. But remember that you should first add a COM reference to the Microsoft Windows Installer Object Library and add the WindowsInstaller namespace to your code. The following function may be what you need.

public static string GetMsiInfo( string msiPath, string Info)
{
   string retVal = string.Empty;

   Type classType = Type.GetTypeFromProgID( “WindowsInstaller.Installer” );
   Object installerObj = Activator.CreateInstance( classType );
   Installer installer = installerObj as Installer;

   // Open msi file
   Database db = installer.OpenDatabase( msiPath, 0 );

   // Fetch the property
   string sql = String.Format(“SELECT Value FROM Property WHERE Property=’{0}’”, Info);
   View view = db.OpenView( sql );
   view.Execute( null );

   // Read in the record
   Record rec = view.Fetch();
   if ( rec != null )
      retVal = rec.get_StringData( 1 );

   return retVal;
}

If you need the version, pass in the name of the MSI file you want, e.g.

string version = GetMsiInfo( "d:\product.msi", “ProductVersion” );

Upvotes: 6

Justin
Justin

Reputation: 86729

Yes - I think you need to inspect the MSI database however, which requires either some API calls or a wrapper utility.

Microsofts ORCA application should let you do this (although I've never tried it myself).

Upvotes: 3

Related Questions