C# 通过Visual Studio安装程序的命令行发送自定义操作数据

C# 通过Visual Studio安装程序的命令行发送自定义操作数据,c#,visual-studio-2010,command-line,installation,custom-action,C#,Visual Studio 2010,Command Line,Installation,Custom Action,我有一个Visual Studio安装程序,它有一个自定义UI,其中有一个文本框,用于恢复设置为QUEUEDIRECTORY属性的值。然后我有一个自定义操作(一个安装程序类),它通过以下行传入该属性值/queuedir=“[QUEUEDIRECTORY]”-安装程序工作得很好 现在,我需要通过命令行发送该值,以便整个组织的系统管理员都可以运行此安装程序。因此,我尝试了以下命令行语句,但它就是不起作用 msiexec /i Setup.msi QUEUEDIRECTORY="D:\temp" Se

我有一个Visual Studio安装程序,它有一个自定义UI,其中有一个文本框,用于恢复设置为
QUEUEDIRECTORY
属性的值。然后我有一个自定义操作(一个安装程序类),它通过以下行传入该属性值
/queuedir=“[QUEUEDIRECTORY]”
-安装程序工作得很好

现在,我需要通过命令行发送该值,以便整个组织的系统管理员都可以运行此安装程序。因此,我尝试了以下命令行语句,但它就是不起作用

msiexec /i Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi queuedir="D:\temp"
msiexec /i Setup.msi queuedir="D:\temp"
此外,我在网上似乎找不到任何让人感觉不到他们入侵的东西,因为他们就是找不到解决方案。我的意思是,我已经找到了一些解决方案,他们正在编辑MSI数据库和所有内容,但这似乎不是正确的解决方案,尤其是自从我使用Visual Studio 2010以来,Microsoft自首次发布此产品以来,确实做了一些增强

这是一个看起来会起作用,但仍然感觉像是一个黑客


无论如何,我希望你能帮助我

好的,所以我最终选择了我在问题中链接的解决方案。但是为了完整起见,让我把脚本放在这里。我需要做的第一件事是构建一个JS文件,该文件包含以下代码(我将其命名为
CommandLineSupport.JS
),并将其放在
.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);
}
当然,您需要通过在Orca中打开MSI并将其与您创建的自定义对话框上的
属性匹配来确保您正在替换正确的
操作

接下来,既然JS文件正常工作了,我需要向
.vdproj
添加一个
PostBuildEvent
,您可以通过单击Visual Studio中的安装项目并点击F4来完成。然后找到
PostBuildEvent
属性并单击省略号。在该
PostBuildEvent
中放置此代码:

cscript "$(ProjectDir)CommandLineSupport.js" "$(BuildOutputPath)Setup.msi"
确保用msi文件名替换
Setup.msi


虽然我仍然觉得这是一个黑客。。。因为它是。。。它起作用了,现在就可以了。这是一个足够小的项目,实际上没什么大不了的。

这就是我在VisualStudio2010中将仅命令行属性值添加到MSI中所做的。这与公认的答案相似,但不太老套。在安装项目(.vdproj)目录中创建
CommandLineSupport.js
,代码如下:

//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);
}
然后在Visual Studio中单击部署项目以查看项目的属性,并将
PostBuildEvent
设置为:

cscript.exe“$(ProjectDir)CommandLineSupport.js”“$(builtoputpath)”

然后使用自定义操作设置Delopyment项目。单击主输出以获取自定义操作属性,并将
CustomActionData
字段设置为
/MYPROPERTY=“[MYPROPERTY]”

然后,您可以在自定义操作安装程序类中访问该属性,如下所示:

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

     string the_commandline_property_value = Context.Parameters["MYPROPERTY"].ToString();
}
INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"'),('MYPROPERTY2', 'MYPROPERTY2=\"\"', ('MYPROPERTY3', 'MYPROPERTY3=\"\"')) ";
最后,您可以运行cmd<代码>C:\>Setup.msi MYPROPERTY=值

这不需要在Orca中进行任何处理,也不需要使用任何自定义对话框控件,如接受答案中的控件。您也不必修改PostBuildEvent来获得正确的.msi名称。等等。还可以添加任意数量的属性,如下所示:

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

     string the_commandline_property_value = Context.Parameters["MYPROPERTY"].ToString();
}
INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"'),('MYPROPERTY2', 'MYPROPERTY2=\"\"', ('MYPROPERTY3', 'MYPROPERTY3=\"\"')) ";

玩得开心

这是一个古老的线程,但有一个更简单、有效的解决方案似乎仍然很难找到,因此我在这里发布它

在我的场景中,我们正在使用VS2013(社区版)和扩展。我们的安装程序项目有一个收集两个用户文本的自定义UI步骤和一个绑定到接收这些文本的Install\Start步骤的自定义操作

我们可以通过GUI安装向导来完成这项工作,但不能通过命令行。最后,接下来,我们还能够使命令行工作,无需任何MSI文件或进行编辑

//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);
}
其要点是直接从Visual Studio为所有需要的自定义对话框属性设置一个值,该值的格式应为
[您的对话框属性名称]
。此外,似乎这些“公共”属性必须用大写字母命名

以下是最终设置:

自定义对话框属性
注释,例如Edit1属性和Edit1值

自定义操作属性
注意:代码后面使用的属性键可以用驼峰大小写命名

自定义操作代码

string companyId = Context.Parameters["companyId"];
string companyApiKey = Context.Parameters["companyApiKey"];
> setup.exe COMPANYID="Some ID" COMPANYAPIKEY="Some KEY" /q /l mylog.txt
命令行

string companyId = Context.Parameters["companyId"];
string companyApiKey = Context.Parameters["companyApiKey"];
> setup.exe COMPANYID="Some ID" COMPANYAPIKEY="Some KEY" /q /l mylog.txt

HTH

与之相关的黑客攻击是真正解决这一问题的唯一方法。当用户界面中有文本框时,生成的Visual Studio MSI文件具有一个无条件自定义操作,该操作将属性设置为空白,因此当您在命令行上指定该属性时,它将被内部自定义操作破坏。