Custom actions that should be standard actions

I recently met a Program Manager who joined Microsoft late last year after working at InstallShield for a while.  We got to talking about some of the difficulties involved in creating an MSI-based setup and the lack of solid, documented best practices and even things that would make it easier to build and test setups such as more comprehensive ICE validation test suites.

One of the interesting discussions we had was to compare lists of actions that are commonly needed in a setup that are not available as MSI standard actions and have to be implemented as custom actions.  Here is his list:

  1. Install kernel mode drivers

  2. Add/remove a line from a text file that is not in INI file format (such as a .NET Framework .config file)

  3. Create user accounts

  4. Change ACLs (since the LockPermissions table does not honor existing ACL’s)

  5. Create a virtual directories in IIS

  6. Create web sites in IIS

  7. Create SQL server databases

  8. List SQL server databases

  9. Create SQL server user accounts

  10. Validate PIDKEY values

  11. To display billboards

  12. An MSI package cannot use mapped drives when an administrator installs an MSI package through a remote session to a terminal server (

  13. Post data to an HTTP server to post information to a organization's web server to record user registration information or other data

  14. Set ALLUSERSPROFILE and USERPROFILE variables in different operating systems

  15. Install a Plug and Play device driver (

  16. User profile creation when a new user logs in

In addition, he made the good point that for every custom action, a setup author has to essentially create 3 custom actions (install, rollback, uninstall) and potentially a 4th (uninstall rollback).

Of the things on this list it was interesting to see that in my experience on the Visual Studio and .NET Framework setup team, we ended up writing custom actions or equivalent code to do items 1, 2, 3, 4, 5, 6, 10, 11, 13 and 16.  Also, the team is working on new custom actions for the SQL items (7, 8, 9).

In addition to the above, I would add the following to the list based on my experience:

  1. Marking folders as hidden (and not just files)

  2. Create user groups

  3. NGEN (pre-JIT) .NET Framework assemblies

  4. Perfomance counter registration

  5. MOF compilation

I'm curious if there are other common custom actions that folks are using that would be useful to have available as standard actions.

For .NET Framework setup developers, I would also like to know if anyone is attempting to implement NGEN functionality within your setup, and if so if you have any feedback about your experiences doing so.

Thanks in advance!

Comments (18)

  1. Steven Bone says:

    Aaron, great list. Items 7-9 related to SQL server items could include a general ability to execute any SQL script, ala ISQL.

    Additionally, the ability to create per-user shortcuts on a per-machine installation would be grand. Why would I want to do this? Policy settings can hide the "All Users" desktop items.

    Number 16, "User profile creation when a new user logs in" is interesting, but having a component that is HKCU when the application shortcut is launched will initiate a repair that can create the profile. Are you referring to a different type of behavior?

    Perhaps the #1 request that I have is persistent properties. I have to implement this type of thing almost all the time and it is horrible. As an example, my setup must install a FlimFlam component with a Timeout registry key, the value of which can be set by the user at install time. I need to provide a default value for this key, preserve the old value for this key if it exists, and update it if the user changes it in maintenance mode. To accomplish this seemingly simple requirement, I must have a property that is used for the registry key, such as "FLIMFLAM_TIMEOUT". I must enter appsearch data to set a property like "AS_FLIMFLAM_TIMEOUT". I then must have a CA that runs after AppSearch to see if the user specified a value for "FLIMFLAM_TIMEOUT" on the command line, if so use it. If "AS_FLIMFLAM_TIMEOUT" is set, update "FLIMFLAM_TIMEOUT" to the value of "AS_FLIMFLAM_TIMEOUT". If neither is set, set "FLIMFLAM_TIMEOUT" to a default value. Then, I need to write ANOTHER CA that tells the MSI to reinstall the ENTIRE FEATURE (rewriting registry values) if the user changes this value in maintenance mode. Heck, if I could call MsiSetComponentState() with a REINSTALL value, that would be awesome!

    Sad to say, I find it impossible to write a one-size-fits-all action for practically all of the tasks you listed. Take #2 "Add/remove a line from a text file that is not in INI file format." Lets say we broke this down into a 2a (Edit XML file) and 2b(Edit any old file). Sounds simple? If you think it is, what is the uninstall or repair behavior? Let’s say you are deploying a web service. You need to edit the WSDL file so it contains the appropriate URL (usually, so it contains the URL for the current machine). What will a repair do – update it? Whatever token existed in this file was already replaced (if treated as a generic text file). If treated as an XML file, the same element can simply be replaced again. When an uninstall happens, is this treated as a user edited file and not removed?

    Let’s take one last example: You need to edit the hosts file. On uninstall what do you do? Remove the edit? If so, you may have caused grief with another install that requires the same change. That means you need to refcount the change. I have no idea how the INI file editing capability of the Windows Installer engine handles this, but whatever the default is, I can come up with a common case where this likely will not work!

    Coming up with actions can be incredibility difficult!

  2. There needs to be a built-in action for installing server controls in the VS.NET toolbox, and a server control deployment project in general.

    Server control development is one of the most overlooked development scenarios in VS.NET. And it shouldn’t be.

  3. David Levine says:

    We have a complex server installation and I found the custom actions to be inadequate for our needs; I wound up writing a custom action that scanned all the assemblies and invoked classes decorated with a custom attribute that indicate to invoke the classes at install time. In essence I created our own version of custom actions.

    One problem is that for multiple installer classes defined within the same assembly it is not possible to define the order the installer classes will be invoked in. It’s also not clear how to pass arguments from one custom action to another.

    One of the custom actions is a class that runs ngen on some assemblies. It would be convenient to have a builtin class that did this but it was pretty easy to write my own.

    All the dialogs are canned and work great….so long as it does exactly what you need it to do. If it doesn’t it is a major PITA to change it. I wound up creating some transforms that I run after the MSI file is created to customize it. One problem was that I wanted to force the client installation to always use the ALLUSERS setting (per-USER not allowed); I removed the radion buttons from the dialog and set the property to the value I needed.

    Things that really really suck…

    1. Performance counter installation is brain-dead. I had to write a fairly complex installation procedure to ensure that it always worked correctly. And there were still some obscure cases that did not work. It’s been a few years and I think it was related to the NT security settings on the registry key where the changes are made to the performance information. Some servers restrict the access rights to one of the keys in HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionPerflib (or perhaps in the 009 subkey). I had to manually adjust the security settings on some servers to get it to work.

    2. Windows installer itself has bugs in how it invokes custom actions. It works great if you run the install or uninstall as completely separate operations, but if you try to use the automatic uninstall/install feature you are in for a nasty surprise. The current implementation creates a single appdomain (the default) out of which it runs all custom actions in managed code, and it never recycles the appdomain. That means that once you load an assembly it stays loaded. This means that if an old assembly runs an uninstall routine, then when the newer version of it is copied to the target, instead of running the install custom action in the new assembly you will actually run the install CA in the old assembly.

    This is bad enough when there is only a single version of the runtime but imagine what would happen if you needed to run the uninstall using an old version of the runtime (eg v1.0) and then run the install using a newer version of the runtime (v1.1)…the install would actually use the old version.

    So I had to disable the automatic update feature in MSI.

    Other custom actions that would be convenient:

    1. Add MIME types to IIS (especially important once server 2003 and XP SP2 ship).

    2. Directly invoke a routine that resets IIS.

    3. There’s probably a lot of security issues related XP SP2 and firewalls that I don’t know about yet.

    Again, I was able to workaround most of these limitations but it took a lot of time.

  4. mgama_123 says:

    Out of curiosity, what’s wrong with the current billboards? I’ve seen some timing issues with billboards, but that’s been the only major nuisance that I had to work around. My solution was to add a blank billboard at the end, to ensure that all of them were displayed (sometimes the final blank one is and some times it isn’t displayed). Sorry, but I don’t care for InstallShield’s own interpretation of billboards (full screen graphics that cover your entire desktop).

    One custom action that most setups need is to allow the user to print the EULA that is presented during setup. I wonder how many times a custom action has been written to print it, or even more simply opened in WordPad?


    Here is an idea for a future blog topic: features that you would like to see built in to Windows Installer. Here are some that I came up with (using, a, b, c, as to not confuse your list with mine):

    a) ControlEvents for radio buttons. It is not currently supported. Checkboxes can have events attached, but not radio buttons.

    b) Ability to embed active X controls. It would be nice to have a Macromedia Flash file as a billboard. Or maybe an IE control to display a small webpage like VS.NET’s setup has (I know they use an external UI for it).

    c) Automatically turning a string like "Please visit our website at {a href=""}{/a}" into a hyperlink. Note, I used curly brackets instead of "less than" and "greater than" because .TEXT would probably strip them.

  5. Aaron Stebner says:

    Ah – the dreaded EULA printing functionality, I forgot about needing a CA to do that because in Visual Studio we used an external UI handler and therefore wrote Win32 code to accomplish that. This is definitely something that needs to be eventually supported by native Windows Installer UI.

    I also really like the idea for the future blog topic about features that we would like to see built into Windows Installer. I’ve got a big mental list of stuff, stay tuned as I get them down in writing and polish them.

    Thanks for reading!

  6. Guru says:

    A simple XSL action where the stylesheet can be an embedded resource or can be an external (installed or existing) xsl file.

    Would also be useful to allow automatic substitution of installer properties in the stylesheet before applying the transform.

    This will help to deal with all sorts of xml configuration files.

  7. Matthew says:

    From a SharePoint perspective I’d love to see:

    1) Installation of Web Part packs (both GAC and BIN options)

    2) Update of non INI files, XML or just text search and replace.

    3) File backup for files edited in #2

    4) A general command line interface that can be executed based on values (radiobuttons or text) in a dialog.

    I’d write more, but now I have to go code all these.

    Thanks for listening.

  8. 1. I agree with the previous comments about persistent property values and text file edits.

    2. Feature dependencies – If you wish to support user advertisement then it is often necessary to have more complicated feature dependencies than the built-in "installing child means installing parent". You will note that the Office team have included a custom table for this purpose (we normally use a custom action).

    We also regularly have to use custom actions for configuring security where the LockPermissions table cannot be used.

    Although not related to custom/standard actions, I think something needs to be done about handling MSI dependencies. Chained installs and/or requiring setup.exe does not cut it in the corporate environment !

  9. Steven, I think that with regards to point 16 Aaron wants the user profile setup to occur before the application icon is selected. Currently this can be hacked using ActiveSetup to do the work (either by called msiexec to initiate a user repair or by blasting the stuff in manually).

    Note that user repairs have to be avoided on terminal servers (only one MSI installation allowed at a time).

  10. says:

    "Let’s take one last example: You need to edit the hosts file. On uninstall what do you do? Remove the edit? If so, you may have caused grief with another install that requires the same change."

    But there is a (large?) class of installs where the file to be edited is simply deleted on uninstall. So a Standard Action to do edit a file to e.g. edit INSTALLDIR would be extremely usefull.

  11. Michael Stuart says:

    I’d like to see a custom action that simply lets you create a shortcut to the virtual directory that your setup package just created. I created my own to do this, but I wish it did that for me.

  12. Rafael says:

    I think that just have the custom action for create an options menu for the re-installing case. Look: on the situation that required to install 2 or more components (services, dlls etc), but on the reinstall, it’s not possible to choice the componets, only all will be reinstalled/fixed.

    If anybody have a suggestion, please send to my mail:

  13. Ramesh says:

    I was looking of implementing copying files based on some condition (I my case I have to decide what kind of hardware platform it is – blade server type).

    This also looks like more common scenario (Copying files based on condtion).

  14. Hi Ramesh – You can use conditions in the Component table of the MSI to install files based on conditions like this.  You shouldn't need a custom action to do that.

  15. Pablo Aliskevicius says:

    I find myself writing code to read a setting from an INI file that is not in the Windows folder, and update a property based on that; this is particularly frequent when updating legacy components.

    Just my two bits…

  16. Michael says:

    Not sure whether the latest Windows installer versions allow this…

    Allow shortcuts to be marked "Run as Administrator" if the target OS has User Account Control.  This would allow creating Start Menu shortcuts to batch files and PowerShell scripts which require elevation for proper execution.

  17. Hi Michael – I don't believe the current version of Windows Installer supports creating that type of shortcut (…/aa371847(v=vs.85).aspx).  In the past, I've written a wrapper .exe that has the requireAdministrator privilege in its manifest to accomplish this type of thing.

Skip to main content