Search code examples
c#visual-studio-2010command-lineinstallationcustom-action

Send Custom Action Data via Command Line for Visual Studio Installer


I have a Visual Studio Installer that has a custom UI with one text box recovering a value that is set to QUEUEDIRECTORY property. Then I have a custom action (an Installer class) that passes in that property value with this line /queuedir="[QUEUEDIRECTORY]" - and the installer works great.

Now, I need to send that value via the command-line so that this installer can be run by system administrators all across the organization. So, I tried the following command line statements but it just doesn't work.

msiexec /i Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi queuedir="D:\temp"
msiexec /i Setup.msi queuedir="D:\temp"

Further, I can't seem to find anything online that doesn't feel like they hacked it because they just couldn't find the solution. I mean I've found some solutions where they are editing the MSI database and everything, but man that just doesn't seem like it's the right solution - especially since I'm using Visual Studio 2010 - Microsoft has surely made some enhancements since its initial release of this offering.

Here is one of the articles that appears would work but still really feels like a hack.

At any rate, I hope that you can help me out!


Solution

  • Alright, so I ended up going with the solution I linked to in the question. But let me put the script here for completeness. The first thing I needed to do was build a JS file that had the following code (I named it CommandLineSupport.js) and put it in the same directory as the .vdproj.

    //This script adds command-line support for MSI build with Visual Studio 2008. 
    var msiOpenDatabaseModeTransact = 1;
    
    if (WScript.Arguments.Length != 1)
    {
        WScript.StdErr.WriteLine(WScript.ScriptName + " file");
        WScript.Quit(1);
    }
    
    WScript.Echo(WScript.Arguments(0));
    var filespec = WScript.Arguments(0);
    var installer = WScript.CreateObject("WindowsInstaller.Installer");
    var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
    
    var sql
    var view
    
    try
    {
        //Update InstallUISequence to support command-line parameters in interactive mode.
        sql = "UPDATE InstallUISequence SET Condition = 'QUEUEDIRECTORY=\"\"' WHERE Action = 'CustomTextA_SetProperty_EDIT1'";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();
    
        //Update InstallExecuteSequence to support command line in passive or quiet mode.
        sql = "UPDATE InstallExecuteSequence SET Condition = 'QUEUEDIRECTORY=\"\"' WHERE Action = 'CustomTextA_SetProperty_EDIT1'";
        view = database.OpenView(sql);
        view.Execute();
        view.Close();
    
        database.Commit();
    }
    catch(e)
    {
        WScript.StdErr.WriteLine(e);
        WScript.Quit(1);
    }
    

    You of course would need to ensure that you're replacing the right Action by opening the MSI in Orca and matching that up to the Property on the custom dialog you created.

    Next, now that I had the JS file working, I needed to add a PostBuildEvent to the .vdproj and you can do that by clicking on the setup project in Visual Studio and hitting F4. Then find the PostBuildEvent property and click the elipses. In that PostBuildEvent place this code:

    cscript "$(ProjectDir)CommandLineSupport.js" "$(BuildOutputPath)Setup.msi"
    

    Making sure to replace Setup.msi with the name of your MSI file.

    Though I still feel like it's a hack ... because it is ... it works and will do the job for now. It's a small enough project that it's really not a big deal.