Is it possible to register environment variables in Setup Wizard project?

Warning: Please do not use this approach. It is dangerous. Use built-in MSI features for environment variable update.

Example: Writing straight to HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment - Path will wipe out whatever is already there. Very serious.

Solution: MSI features the Environment table to facilitate merging and updating of environment variables in a reliable fashion. Note that this table is also known to be complex enough to trigger unexpected results. Please test well. Uninstall scenarios especially.


Using Visual Studio 2008, you can easily do it by setting the appropriate variable in the Windows registry:

  1. In the Solution Explorer, right-click on your project (not solution), and select View->Registry
  2. Create the registry key(folder):
    1. For a User variable: Right-click on HKEY_CURRENT_USER, select "New Key", and name it "Environment".
    2. For a System variable: Right-Click on HKEY_LOCAL_MACHINE, select "New Key", and name it "SYSTEM". Continue doing this to create the path "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" .
  3. Right-click on the Environment key(folder), select New->String, and give it the name you want.
  4. With the string selected, find the Properties window (Alt+Enter will bring it up)
  5. In the Properties window, fill in the Value you want.

If you want the Value to reference the installation directory, you can do it like this using property variables: [TARGETDIR]SomeFile.ext (see http://msdn.microsoft.com/en-us/library/aa370905%28v=vs.85%29.aspx for more property variables)


Windows Installer does support environment variables through Environment table, but Visual Studio setup projects do not allow you to use it.

A solution is to use a different setup authoring tool which supports environment variables: http://en.wikipedia.org/wiki/List_of_installation_software

Another solution is to manually add it in Environment table by editing the MSI with Orca.

There's also the custom action approach you mentioned.


The top answer explains how to do it without a custom action but those looking for a custom action can use the following code as a template:

 [RunInstaller(true)]
public partial class GRInstallCustomAction : System.Configuration.Install.Installer
{
    string environmentKey = @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment";
    string pathUrl = "C:\\Program Files (86)\\TargetFolder";
    public GRInstallCustomAction()
    {
        InitializeComponent();
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);
    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Commit(IDictionary savedState)
    {
        base.Commit(savedState);

        string environmentVar = Environment.GetEnvironmentVariable("PATH");


        //get non-expanded PATH environment variable            
        string oldPath = (string)Registry.LocalMachine.CreateSubKey(environmentKey).GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);


        var index = oldPath.IndexOf(pathUrl);
        if (index < 0)
        {
            //set the path as an an expandable string
            Registry.LocalMachine.CreateSubKey(environmentKey).SetValue("Path", oldPath + ";" + pathUrl, RegistryValueKind.ExpandString);
        }

    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Rollback(IDictionary savedState)
    {
        base.Rollback(savedState);


    }

    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
    public override void Uninstall(IDictionary savedState)
    {
        base.Uninstall(savedState);

        //get non-expanded PATH environment variable            
        string oldPath = (string)Registry.LocalMachine.CreateSubKey(environmentKey).GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);

        string removeString = pathUrl + ";";
        var index = oldPath.IndexOf(removeString);
        if (index < 0)
        {
            removeString = pathUrl;
            index = oldPath.IndexOf(removeString);
        }

        if (index > -1)
        {
            oldPath = oldPath.Remove(index, pathUrl.Length);
            //set the path as an an expandable string
            Registry.LocalMachine.CreateSubKey(environmentKey).SetValue("Path", oldPath, RegistryValueKind.ExpandString);
        }
    }
}

This walk-through shows you how to create and apply the custom action: https://msdn.microsoft.com/en-us/library/d9k65z2d(v=vs.100).aspx