Click here to Skip to main content
Click here to Skip to main content

Creating a SMS Package from a MSI File using Microsoft's SMS.DLL

, 2 Dec 2007
Rate this:
Please Sign up or sign in to vote.
Create a Systems Management Server Package from an MSI file using the SMS toolkit.

Introduction

Normally Systems Management Server(SMS) Packages are created by using the SMS AdminstratorConsole. For automation purposes, sometimes a programmatic way is needed to create a package from a *.msi Installer file. The Systems Management Server 2003 Software Development Kit (see the Microsoft® SMS SDK) only supports the creation of an SMS package from a *.pdf file. To create a package from a *.msi file, a workaround is needed.
The idea is quite simple: reading the attributes out of the MSI database and adding them to a manually created SMS package.

To use the code in the demo project, just include a reference to msi.dll (usually found in system32). If you include it with Visual Studio (Project + Add Reference, COM tab, select "Microsoft Windows Installer Object Library") it generates a wrapper called Interop.WindowsInstaller.dll.

You also need a reference to Microsoft.SystemsManagementServer.Automation.dll which can be downloaded here.

If you download both files (Interop.WindowsInstaller.dll and Microsoft.SystemsManagementServer.Automation.dll) and copy them into the lib folder of the sample project, all references are OK because I set the references to this folder.

Using the Code

First we have to determine the attributes of the MSI database. To read the MSI database, we need to import the Microsoft® Windows Installer (see the Microsoft® Windows Installer Reference). It is defined as a COM import and has to be declared in the class:

[System.Runtime.InteropServices.ComImport(),
    System.Runtime.InteropServices.Guid
    ("000C1090-0000-0000-C000-000000000046")]
class Installer { }

Now we are able to query the MSI file.
As described in other tutorials, we do this in these steps:

  1. Open the MSI database/file
  2. Query the database
  3. Store the Attributes in a Hashtable for further use
// snippet of demo projects' "DetermineMsiData()" method



// get the MSI file


FileInfo msiFile = new FileInfo("c:\\MyPath\\MyInstallerFile.msi")

// Hashtable to store the attributes of the MSI


Hashtable msiData = new Hashtable();

// open MSI database


WindowsInstaller.Installer inst = (WindowsInstaller.Installer)new Installer();
Database instDb = inst.OpenDatabase(msiFile.FullName,
    WindowsInstaller.MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly);

// query the database


WindowsInstaller.View view = instDb.OpenView
    ("Select `Property`,`Value` FROM `Property`");
view.Execute(null);
Record record = view.Fetch();

//fetch the data and store it in a hash table


while (record != null)
{
    //debug


    Console.WriteLine(record.get_StringData(1)+"|"+record.get_StringData(2));

    //add data to hash table


    msiData.Add(record.get_StringData(1), record.get_StringData(2));
    record = view.Fetch();
}

// close the database


view.Close();  

The next thing to do is to build the new SMS package with the data stored in the msiData Hashtable. This can be done with the following steps:

  1. Connect to the SMS server
  2. Create a new SMS package
  3. Add the attributes stored in msiData
// snippet of demo projects' "createPackageFromMsi()" method



SMSProvider smsProvider = null

// connect to the SMS server


try
{
    String smsServer="\\\\root\\sms\\site_";
    smsProvider = new SMSProvider(smsServer, "myUserName", "myPassword");
}
catch(Exception ex)
{
    Console.Error.WriteLine("Could not connect to the SMS Provider.",ex);
    MessageBox.Show("Could not connect to the SMS Provider.");
}

// create a new package if a product name is given in the msiData Hashtable


SMSPackage smsPkg;
if(msiData.ContainsKey("ProductName"))
{
    smsPkg = smsProvider.Packages.Create(msiData["ProductName"].ToString());
}
else
{
    Console.Error.WriteLine("msi contains no product name.");
    return null;
}

// add the attributes of the MSI to the new created PDF


if(msiData.ContainsKey("ProductLanguage"))
{
    smsPkg.Language = msiData["ProductLanguage"].ToString();
    Console.WriteLine("set smsPkg.Language="+
        msiData["ProductLanguage"].ToString());
}

// .... add other attributes (Manufacturer, ProductName, Productversion) 


//      the same way like ProductLanguage. Take a look at the demo project.




// setting the filename and the SMS package source path eg.: c:\temp\sourcen


smsPkg.MIFFileName = msiFile.Name;
Console.WriteLine("set smsPkg.MIFFileName="+ msiFile.Name);

smsPkg.PkgSourcePath = "c:\\temp\\sourcen";
Console.WriteLine("set smsPkg.PkgSourcePath="+  smsPkg.PkgSourcePath); 

Now we have to create the install and uninstall programs. Despite a *.pdf file, the *.msi file does not contain the install or uninstall programs.
Therefore we will create them manually.

// also part of the demo projects' "createPackageFromMsi()" method


//create programs: install/uninstall


String name = "Installation (Service)";
String cmd = "msiexec.exe /q ALLUSERS=2 /i \""+msiFile.Name+"\"";

Console.WriteLine("creating install program: Name= "+name+"  CMD= "+cmd);
SMSProgram inst = smsPkg.Programs.Create(name,cmd);
inst.RunWithAdminRights = true;
inst.UserRequirements = UserRequirementsFlags.RunWhether
gedOnOrOff;
inst.Save();

name = "Uninstall (Service)";
cmd = "msiexec.exe /q /x \""+msiFile.Name+"\"";

Console.WriteLine("creating install program: Name= "+name+"  CMD= "+cmd);
SMSProgram deInst = smsPkg.Programs.Create(name,cmd);
deInst.RunWithAdminRights = true;
deInst.UserRequirements = UserRequirementsFlags.RunWhetherLoggedOnOrOff;
deInst.Save(); 

Last but not least we have to save the SMS package. The Save method stores the changes we made in the SMS server.

// also part of the demo projects "createPackageFromMsi()" method


// save the attributes set to the SMS package


smsPkg.Save();
Console.WriteLine("SMS package with id: "+smsPkg.PackageID+" created.")

This is quite a simple solution, but works fine. The Microsoft SMS toolkit is a big help while developing custom SMS solutions. Unfortunately the documentation is not so good and the support for *.msi files is missing.

Points of Interest

If you want to determine the Siteservername out of the registry, you can find it under:

  • Microsoft.Win32.Registry.CurrentUser Software\Microsoft\SMS\Admin UI\MRU\Site1\ServerName
    or
  • Microsoft.Win32.Registry.LocalMachine Software\Microsoft\SMS\AdminUI\Connection\Server

First try to get the Servername out of HKCU, then from HKLM.
The demo project demonstrates how to determine the server out of the registry and how to connect to it. If you have questions about the programmatic use of the SMS Server, please feel free to contact me.

References

Please feel free to browse the following reference material:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Daniel Wasser
Web Developer
Germany Germany
I'm a Cologne based software developer
specialized in object orientated languages.
 
I use Java and C# to develop all kind of software, mostly Portal- and GUI- applications or web services.
 
At the moment I'm working as freelancer for my customers from government and the telecommunication industry.
 
CodeProject saved my live a lot of times and I would like to thank the team and the community.
 
If you are interested in more code snippets, feel free to visit my blog.

Comments and Discussions

 
-- No messages --
Try changing the 'Date Filter' value
| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 2 Dec 2007
Article Copyright 2007 by Daniel Wasser
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid