2
votes

How can I author a WiX custom action that

  1. Is always called at the end of an installation, at least if there's an install error
  2. Copies the current MSI log file from its current local to the user's APPDATA folder

I have this managed custom action code. Not sure how to author its invocation in my Wix script. Should the custom action be scheduled for after InstallFinalize? Can it be scheduled OnExit="error"?

    [CustomAction]
    public static void CopyLogFile(Session session)
    {
        const string company = "MyCompany";
        const string product = "MyProduct";
        try
        {
            session.Log("CustomAction.CopyLogFile entry");

            var msiLogFilePath = session.CustomActionData["LOGFILEPATH"];
            if (msiLogFilePath != null)
            {
                session.Log("CustomAction.CopyLogFile MSI log filename: {0}", msiLogFilePath);

                var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                var destDirPath = Path.Combine(localAppDataPath, company, product);

                var destDir = Directory.CreateDirectory(destDirPath);
                session.Log("CustomAction.CopyLogFile Destination directory: {0}", destDir.FullName);

                var destFilePath = Path.Combine(destDir.FullName, Path.GetFileName(msiLogFilePath));
                File.Copy(msiLogFilePath, destFilePath, true);

                session.Log("CustomAction.CopyLogFile Log file copied to: {0}", destFilePath);
            }
            else
            {
                session.Log("CustomAction.CopyLogFile File path not found");
            }
        }
        catch (Exception exception)
        {
            session.Log("CustomAction.CopyLogFile exception {0}", exception);
        }
        finally
        {
            if (session != null)
            {
                session.Log("CustomAction.CopyLogFile exit");
                session.Close();
            }
        }
    }
2

2 Answers

2
votes

Yes, you can schedule it after InstallFinalize (so did I, but I copy it every time if it is not a complete removal of the package):

<InstallExecuteSequence>
    <Custom Action="CopyLogfile" After="InstallFinalize">NOT (REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE)</Custom>
</InstallExecuteSequence>

Remember to also add it to the UI sequence if you have any. I added it as event to the PushButton in the SetupCompleteSuccess- and SetupCompleteError-dialogs (maybe you need to add it only to the latter one?) like in the following:

<Dialog Id="SetupCompleteSuccess" X="50" Y="50" Width="374" Height="266" Title="[ProductName]" NoMinimize="yes">
     <Control Id="OK" Type="PushButton" X="230" Y="243" Width="66" Height="17" Text="&amp;Finish" TabSkip="no" Default="yes" Cancel="yes">
           <Publish Event="EndDialog" Value="Exit">1</Publish>
           <!-- ### Invoking copying the logfile if the Finish-button is pressed -->
           <Publish Event="DoAction" Value="CopyLogfile">MsiLogFileLocation AND NOT (REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE)</Publish>
    </Control>
 <!-- ... rest of the dialog ... -->
</Dialog>

Regarding showing it only in case of an error: Maybe checking for the ProductState-properrty? Searched the web for this but didn't find anything useful.

Edit: Maybe a proper way to execute it only in case of an error is the usage of Custom Action flags that execute it only during rollback. In WiX it would be the Execute="rollback"-attribute for the CustomAction-tag.

1
votes

Don't mess with custom actions after InstallFinalize if you can help it. They are often skipped entirely when deploying via tools such as SCCM, Unicenter, etc...

A custom dialog with a button to open the log file at the end of the install could work ok though.