1

I am using Wix version 3.9R2

I followed the suggestions here to create persistable properties across installs/repairs/uninstalls of my product.

When I am installing, the properties set from the command-line get sent correctly to my custom action method. When I re install the product they do not, although the log shows that the properties are populated with the correct values. Here are my install logs (both install and repair).

Also, here is my wxs file. I omitted some parts that I don't think were relevant.

<?xml version="1.0" encoding="UTF-8"?>
<Wix>
  <Product>

    <!--These are all of our properties that we can configure-->
    <Property Id="APPPOOLUSERACCOUNTTYPE" Value="networkService" />
    <Property Id="APPPOOLUSERNAME" Value="Username" />
    <Property Id="APPPOOLUSERPASSWORD" Value="Password" />
    <Property Id="DATABASECONNECTIONSTRING">
      <RegistrySearch Id="DatabaseConnectionStringProperty" Root="HKLM"
                      Key="SOFTWARE\MedXStorage\Database"
                      Name="ConnectionString" Type="raw" />
    </Property>
    <Property Id="DATABASENAME">
      <RegistrySearch Id="DatabaseNameProperty" Root="HKLM"
                      Key="SOFTWARE\MedXStorage\Database"
                      Name="DatabaseName" Type="raw" />
    </Property>

    <!--Actions to restore any settings set from the command line-->
    <CustomAction Id="DATABASECONNECTIONSTRING_SaveCmdLineValue" Property="CMDLINE_DATABASECONNECTIONSTRING" Value="[DATABASECONNECTIONSTRING]" Execute="firstSequence" />
    <CustomAction Id="DATABASECONNECTIONSTRING_SetFromCmdLineValue" Property="DATABASECONNECTIONSTRING" Value="[CMDLINE_DATABASECONNECTIONSTRING]" Execute="firstSequence" />
    <CustomAction Id="DATABASENAME_SaveCmdLineValue" Property="CMDLINE_DATABASENAME" Value="[DATABASENAME]" Execute="firstSequence" />
    <CustomAction Id="DATABASENAME_SetFromCmdLineValue" Property="DATABASENAME" Value="[CMDLINE_DATABASENAME]" Execute="firstSequence" />

    <!--Action that deploys the database-->
    <CustomAction Id="DeployDatabaseAction"
               BinaryKey="MedXStorage.InstallerActions.dll"
               DllEntry="DeployDatabase" />

    <InstallExecuteSequence>
      <!--Restore and settings set from the command line-->
      <Custom Action="DATABASECONNECTIONSTRING_SaveCmdLineValue" Before="AppSearch" />
      <Custom Action="DATABASECONNECTIONSTRING_SetFromCmdLineValue" After="AppSearch">CMDLINE_DATABASECONNECTIONSTRING</Custom>
      <Custom Action="DATABASENAME_SaveCmdLineValue" Before="AppSearch" />
      <Custom Action="DATABASENAME_SetFromCmdLineValue" After="AppSearch">CMDLINE_DATABASENAME</Custom>
      <!--Lets try to deploy our datbase-->
      <Custom Action="DeployDatabaseAction" After="InstallInitialize">
        <![CDATA[&DatabaseFeature=3 OR REINSTALL><DatabaseFeature]]>
      </Custom>
    </InstallExecuteSequence>

    <InstallUISequence>
      <!--Restore and settings set from the command line-->
      <Custom Action="DATABASECONNECTIONSTRING_SaveCmdLineValue" Before="AppSearch" />
      <Custom Action="DATABASECONNECTIONSTRING_SetFromCmdLineValue" After="AppSearch">CMDLINE_DATABASECONNECTIONSTRING</Custom>
      <Custom Action="DATABASENAME_SaveCmdLineValue" Before="AppSearch" />
      <Custom Action="DATABASENAME_SetFromCmdLineValue" After="AppSearch">CMDLINE_DATABASENAME</Custom>
    </InstallUISequence>

  </Product>
</Wix>

Here is my C# action method.

[CustomAction]
public static ActionResult DeployDatabase(Session session)
{
    try
    {
        session.Log("Begin DeployDatabase");

        var connectionString = session["DATABASECONNECTIONSTRING"];
        var databaseName = session["DATABASENAME"];
        var dacpacLocation = session["DATABASEDACPACLOCATION"];

        session.Log("Starting database deploy with...");
        session.Log("   ConnectionString=" + connectionString);
        session.Log("   DatabaseName=" + databaseName);
        session.Log("   DacpacLocation=" + dacpacLocation);

        if (string.IsNullOrEmpty(connectionString))
        {
            session.Log("Connection string must be provided.");
            return ActionResult.Failure;
        }

        if (string.IsNullOrEmpty(connectionString))
        {
            session.Log("Database name must be provided.");
            return ActionResult.Failure;
        }

        if (string.IsNullOrEmpty(dacpacLocation))
        {
            session.Log("Dacpac must be provided.");
            return ActionResult.Failure;
        }

        if (!File.Exists(dacpacLocation))
        {
            session.Log("The dacpac doesn't exist at " + dacpacLocation + ".");
            return ActionResult.Failure;
        }

        SqlPackage.Deploy(dacpacLocation, connectionString, databaseName, (messageType, message) => session.Log("Sql deploy message: " + messageType + ": " + message));

        return ActionResult.Success;
    }
    catch (Exception ex)
    {
        session.Log("Error deploying database.");
        var exception = ex;
        while (exception != null)
        {
            session.Log("---");
            session.Log("Message:" + exception.Message);
            session.Log("Stacktrace:" + exception.StackTrace);
            session.Log("---");
            exception = exception.InnerException;
        }
        return ActionResult.Failure;
    }
}

In the repair logs, you can see it setting the properties correctly.

Property(C): DATABASECONNECTIONSTRING = Data Source=(localdb)\ProjectsV12;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False

However, in my custom action, I can't retrieve this property.

Starting database deploy with...
   ConnectionString=
   DatabaseName=
   DacpacLocation=C:\Users\Paul\AppData\Local\Temp\tmpA791.tmp

Why does this same msi give me the correct properties values during install, but none on repair?

Paul Knopf
  • 9,568
  • 23
  • 77
  • 142

2 Answers2

3

WiX uses the Secure attribute on the Property element to build the SecureCustomProperties property.

The SecureCustomProperties is a list of public properties delimited by semi-colons. These properties are included with the default list of restricted public properties that the installer can pass to the server side when doing a managed installation with elevated privileges.

FWIW, the remember me property pattern is incomplete in my opinion. I usually take it a bit farther to implement a property source precedence pattern also. The idea is that a value passed at the command line or selected in the UI should override the remembered value which should override the default value.

Christopher Painter
  • 54,556
  • 6
  • 63
  • 100
3

Properties should be marked Secure=:yes" if they are to be transferred from the UI sequence into the server's execution sequence - that might be the issue.

PhilDW
  • 20,260
  • 1
  • 18
  • 28