Mike Perrenoud
Mike Perrenoud

Reputation: 67898

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!

Upvotes: 1

Views: 2898

Answers (3)

superjos
superjos

Reputation: 12695

This is an old thread, but there's a simpler, working solution that still seems hard to find, hence why I'm posting it here.

In my scenario we're working with VS2013 (Community Ed.) and VS 2013 Installer Project extension. Our installer project has a custom UI step collecting two user texts and a custom action bound to Install\Start step that receives those texts.

We were able to make this work from GUI setup wizard, but not from command line. In the end, following this workaround, we were able to make also command line work, without any MSI file Orca editing.

The gist of the thing was to set a value for all needed custom dialog properties directly from Visual Studio, and such value should be in the form [YOUR_DIALOG_PROPERTY_NAME]. Also, it seems like such "public" properties must be named in all caps.

Here's the final setup:

Custom dialog properties
Note e.g. Edit1Property and Edit1Value.

enter image description here

Custom action properties
Note as property key used later in code can be named in camel case.

enter image description here

Custom action code

string companyId = Context.Parameters["companyId"];
string companyApiKey = Context.Parameters["companyApiKey"];

Command line

> setup.exe COMPANYID="Some ID" COMPANYAPIKEY="Some KEY" /q /l mylog.txt

HTH

Upvotes: 0

D Sander
D Sander

Reputation: 21

This is what I did to add command line only property values to my MSI in Visual Studio 2010. It's similar to the accepted answer, but less hacky. Create CommandLineSupport.js in setup project (.vdproj) directory, with the following code:

//This script adds command-line support for MSI installer
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
{

    sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"')";
    view = database.OpenView(sql);
    view.Execute();
    view.Close();

    database.Commit();
}
catch(e)
{
    WScript.StdErr.WriteLine(e);
    WScript.Quit(1);
}

Then click on your Deployment Project in Visual Studio to view the Properties of the project, and set the PostBuildEvent to this:

cscript.exe "$(ProjectDir)CommandLineSupport.js" "$(BuiltOuputPath)"

Then set up the Delopyment Project with a Custom Action. Click on the Primary Output to get to the Custom Action Properties, and set the CustomActionData field to /MYPROPERTY="[MYPROPERTY]"

You can then access that property in your Custom Action installer class like this:

public override void Install(IDictionary stateSaver)
{
     base.Install(stateSaver);

     string the_commandline_property_value = Context.Parameters["MYPROPERTY"].ToString();
}

In the end you can run the cmd. C:\>Setup.msi MYPROPERTY=VALUE

This doesn't require any messing about in Orca, or using any custom dialog controls like in the accepted answer. You don't have to modify the PostBuildEvent to have the correct .msi name either. Etc. Also can add as many properties as you wish like this:

INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"'),('MYPROPERTY2', 'MYPROPERTY2=\"\"', ('MYPROPERTY3', 'MYPROPERTY3=\"\"')) ";

Have fun!

Upvotes: 2

Mike Perrenoud
Mike Perrenoud

Reputation: 67898

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.

Upvotes: 0

Related Questions