WIX CustomAction - how to get more info in install/log - wix

Someone told me there was a way for the CustomAction in WIX to display the output in the console log. I'm including an .exe called XmlPreprocess.exe to manipulate my web.config, based on parms in a file called SettingsFileGenerator.xml,
I'm running like this:
msiexec /i bin\Debug\TFBIC.RCT.WCFWebServicesWIXSetup.msi /L*V "C:\logs\WixInstall01.log"
This is my WIX build file:
<CustomAction Id="**SAMPLE_CONFIG**" BinaryKey="XMLPREPROCESS" ExeCommand="/i:"[INSTALLLOCATION]web.config" /x:"[INSTALLLOCATION]SettingsFileGenerator.xml" /e:QA /d:ServiceLocation=[SERVICELOCATION]" Execute="deferred" />
<Binary Id="XMLPREPROCESS" SourceFile="../TFBIC.RCT.WCFWebServices/RequiredBins/XMLPreprocess.exe" />
<InstallExecuteSequence>
<Custom Action="SAMPLE_CONFIG" After="StartServices"><![CDATA[NOT Installed]]></Custom>
</InstallExecuteSequence>
Install log shows this:
Action 15:22:27: StartServices. Starting services
Action start 15:22:27: StartServices.
MSI (s) (58:CC) [15:22:27:898]: Note: 1: 2205 2: 3: ServiceControl
MSI (s) (58:CC) [15:22:27:898]: Note: 1: 2228 2: 3: ServiceControl 4: SELECT `Name`,`Wait`,`Arguments`,`Event`, `Action` FROM `ServiceControl`, `Component` WHERE `Component_` = `Component` AND (`Action` = 0 OR `Action` = 1 OR `Action` = 2)
Action ended 15:22:27: StartServices. Return value 1.
MSI (s) (58:CC) [15:22:27:899]: Doing action: SAMPLE_CONFIG
Action 15:22:27: SAMPLE_CONFIG.
Action start 15:22:27: **SAMPLE_CONFIG**.
SAMPLE_CONFIG:
Action ended 15:22:27: **SAMPLE_CONFIG**. Return value 1.
This is my very first attempt to do WIX, so please bear with my ignorance.
Thanks
UPDATE:
This is a quote from another forum - but he doesn't specify how it works and he doesn't seem to check back often.
WiX has a custom action that captures
the console output and sticks it
directly into the verbose MSI log, so
that's what I use.
reference: http://xmlpreprocess.codeplex.com/Thread/View.aspx?ThreadId=79454
Would this be the tool he is talking about?
http://wix.sourceforge.net/manual-wix2/qtexec.htm
I get this error when trying it:
error LGHT0103: The system cannot find the file 'wixca.dll'.
I have searched entire disk for this .dll and could not find it.

To enable all possible logging while installing an msi, use the /lvx* logfile.txt option. However, even this will not log the STDOUT and STDERR output of command line applications invoked as a custom action.
If you have written the custom action yourself, you can add such logging to it. For example, the DTF libraries that come with wix have a handy Session.Log method that you can call. See c:\program files\windows installer xml v3\doc\dtf.chm, topic "Writing Managed Custom Actions" for more information.
If you have not written the application, you could write a custom action to wrap it. Such a wrapper could use the .NET Process class to invoke an executable, read the StandardError and StandardOutput streams, and log everything with the Session.Log method mentioned above.
edit: I don't know of any standard custom action in wix that sends console output to the log. Try the wix-users mailing list.

In Wix 3.10 you can use the Quiet Execution custom action to run an executable (silently, e.g. without a command window popup), and the console output will end up in the msi log.
As mentioned, you need the WixUtilExtension reference to get access to this feature.

Related

WIX MSI: I Want to show a message to user "Product is already Installed" if user runs the installer again

I am creating an MSI installer, during testing the same if I am running the installer for the first time the installer works as expected. But when I accidentally run the installer, it uninstalled my files.
So, for that, I had modified the condition and added Remove="All" in the condition of the actions.
Which is working fine, but I want to show a message to the User that the product is already installed.
So, for that, I added the below piece of code:
<Upgrade Id='<<Upgrade Code>>'>
<UpgradeVersion OnlyDetect='yes' Property='SELFFOUND'
Minimum='1.0.1' IncludeMinimum='yes' Maximum='1.0.1' IncludeMaximum='yes' />
<UpgradeVersion OnlyDetect='yes' Property='NEWERFOUND'
Minimum='1.0.1' IncludeMinimum='no' />
</Upgrade>
<CustomAction Id='AlreadyUpdated' Error='[ProductName] is already installed.' />
.....
.....
.....
.....
.....
<InstallExecuteSequence>
<Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
</InstallExecuteSequence>
But when running this, the installer is still running for the second time and not giving the message.
On checking the logs, could see that the "FindRelatedProducts" skipped with the below message:
MSI (c) (F4:1C) [06:18:04:806]: Doing action: FindRelatedProducts
MSI (c) (F4:1C) [06:18:04:806]: Note: 1: 2205 2: 3: ActionText
Action 6:18:04: FindRelatedProducts. Searching for related applications
Action start 6:18:04: FindRelatedProducts.
MSI (c) (F4:1C) [06:18:04:806]: Skipping FindRelatedProducts action: not run in maintenance mode
Action ended 6:18:04: FindRelatedProducts. Return value 0.
and
MSI (s) (18:14) [06:18:05:500]: Running ExecuteSequence
MSI (s) (18:14) [06:18:05:500]: Doing action: FindRelatedProducts
MSI (s) (18:14) [06:18:05:500]: Note: 1: 2205 2: 3: ActionText
Action 6:18:05: FindRelatedProducts. Searching for related applications
Action start 6:18:05: FindRelatedProducts.
MSI (s) (18:14) [06:18:05:507]: Skipping FindRelatedProducts action: already done on client side
Action ended 6:18:05: FindRelatedProducts. Return value 0.
The condition in AlreadyUpdated custom action also does not satisfy.
MSI (s) (18:14) [06:18:05:737]: Doing action: PublishProduct
MSI (s) (18:14) [06:18:05:737]: Note: 1: 2205 2: 3: ActionText
Action 6:18:05: PublishProduct. Publishing product information
Action start 6:18:05: PublishProduct.
PublishProduct:
MSI (s) (18:14) [06:18:05:752]: Re-publishing product - installing new package with existing product code.
Action ended 6:18:05: PublishProduct. Return value 1.
MSI (s) (18:14) [06:18:05:752]: Skipping action: AlreadyUpdated (condition is false)
Is there any way to achieve this requirement? Am I doing something wrong?
Custom Action Complexity: First a word on custom actions and their complexity. Please read the first paragraphs here:
Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?
Wrong Conditioning: This basically means your conditions are incorrect so the custom actions run in installation modes where they should not. There are many installation modes you should test in when you try to use complex conditions (or any condition for that matter): 1. fresh install, 2. repair, 3. modify, 4. self-repair, 5. patching, 6. uninstall, 7. major upgrade invoked uninstall, etc...
In your case some custom actions run on maintenance run as well as during fresh / first installation. This is a very common problem. The solution is either to eliminate the custom actions by improving the setup, or to improve conditions so they actually work in any installation mode. Obviously.
Condition Debugging: Conditions are hard to get right. I like to test them using message boxes. The bottom section here shows how you can do so: How to execute conditional custom action on install and modify only? - then you run the setup in different modes and look for the dialog boxes. When they show up the condition on the custom action is true.
Complex Conditions:
Here is an answer on why old custom actions are used for a new setup: Wix Tools update uses old custom actions.
There is also an answer listing some values for common properties in different installation modes: How to add a WiX custom action that happens only on uninstall (via MSI)?
Installshield has this PDF of common conditions (some of which are Installshield-specific): https://resources.flexera.com/web/pdf/archive/IS-CHS-Common-MSI-Conditions.pdf
Unexpected Behavior: A special note on the properties UPGRADINGPRODUCTCODE and WIX_UPGRADE_DETECTED. Please read this: Run Wix Custom action only during uninstall and not during Major upgrade - these quirks affect how many times a custom action runs during a major upgrade scenario. Some very surprising effects here for people. Use your message box debugging?
Links:
wix installer update process and confirmation dialog
Wix custom uninstallation action - how to run before msi removing files
Installing driver using cutomAction DriverPackageInstall in wix installer
WIX CustomAction conditions
Failed to get MSI property in UPGRADINGPRODUCTCODE, WIX_UPGRADE_DETECTED
Reboot on install, Don't reboot on uninstall

A type 2 Custom Action is failing to execute on InstallUISequence while it is executed if put on InstallExecuteSequence

I have a Type 2 Custom Action which is executing an executable file with parameters.
I need to execute this CA before InstallWelcome dialog because it is used to collect some information to pre populate a dialog later.
So I sequenced this CA after CostFinalize action in the InstallUISequence but the installer fails to execute it with an error like below.
If I move the CA in the InstallExecuteSequence sequence it is executed as expected. (As explained in a later comment this is not true, it fails also in this sequence).
Does anyone have any idea what might happened?
Maybe useful information: If same executable is used in a Type 18 Custom Action (the executable is installed with the application's binaries) it is executed without problem.
<CustomAction Id='RunEXE' BinaryKey='EditCfg.exe.CA.ID' ExeCommand='[INSTALLFOLDER][SEPARATOR][CONFIG_FILE_NETWORK_LOCATION][SEPARATOR][USER_NAME][SEPARATOR][PASSWORD][SEPARATOR][WIX_UPGRADE_DETECTED][SEPARATOR][CHECKED_RULE][SEPARATOR][CERTIFICATE_LOCATION]' Execute='immediate' Impersonate='no' Return='check' />
<Binary Id='EditCfg.exe.CA.ID' SourceFile='path_to_the_exe_file'/>
MSI (c) (14:04) [15:18:36:452]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1722
Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action RunEXE, location: C:\Users\yyyyy\AppData\Local\Temp\MSIC8A9.tmp, command: param1§param2§param3§§param5§§param7
The 1722 error indicates that the exe returned a non-zero exit code. If this is expected, you can alter the Return attribute to use ignore instead of check. But if it's not expected, you probably need to figure out what that return code indicates, as odds are high that it's some sort of failure.
Here are a couple things that might cause failures:
The exe file may have some dependencies. Putting just the exe in the binary table doesn't carry its dependencies with it, so attempts to load and run the exe may fail, even before it gets to the exe's main code, depending on the kind of dependency.
When executed as a file installed with the product, the file may not exist in the specified location as of the time the custom action executes. During installation, new files do not show up until a deferred/in-script action after InstallFiles (or regular scheduling after InstallExecute); during uninstallation they often disappear by RemoveFiles. Maintenance can be a combination of those. However, a missing exe would likely result in a 1721 error instead of a 1722 error.
Regardless, note that exe custom actions cannot communicate useful data back to the Windows Installer session, so it will be difficult to leverage any data it finds (or creates) in the UI without the help of additional DLL-based actions or system searches. If you also add a DLL-based action, you may find it more friendly to launch the exe from that action (or even fully incorporate what it does into the dll), as you can log better diagnostics than the generic ones you've seen here.

Executing wix msi custom actions as system

I am using WIX to build a an MSI that will be executed as a regular user but with system privileges (AlwaysInstallElevated=1). I have defined two Custom Actions that execute net.exe.
The net.exe commands are not getting executed as a regular user. I have also tested executing this msi as an Administrator and the net.exe commands are getting executed.
I have logged the msi output and I see error codes that lead me to believe that the net.exe commands are not being executed elevated. I'm reaching out to the community to see if
What I'm trying to do is possible
Do I need to instead use an exe as a custom action in order for the exe to install elevated.
Thanks in advance for the feedback.
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe user TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command1">Command1</CustomAction>
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe localgroup Administrators TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command2">Command2</CustomAction>
<InstallExecuteSequence>
<Custom Action="Command1" After="PublishProduct">NOT Installed</Custom>
<Custom Action="Command2" After="Command1">NOT Installed</Custom>
</InstallExecuteSequence>
Machine Policy and User policy allows for msis to be executed as system.
MSI (c) (DC:F8) [09:17:39:438]: Machine policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: User policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: Running product '{34ED8E61-40EA-47CE-95E7-8EE3CDBCB1E8}' with elevated privileges: All apps run elevated.
Errors
MSI (s) (8C:8C) [20:39:18:989]: Executing op: ActionStart(Name=Command1,,)
MSI (s) (8C:8C) [20:39:18:989]: Executing op: CustomActionSchedule(Action=Command1,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe user TestUser /add,)
CustomAction Command1 returned actual error code 2 but will be translated to success due to continue marking
MSI (s) (8C:8C) [20:39:19:535]: Executing op: ActionStart(Name=Command2,,)
MSI (s) (8C:8C) [20:39:19:535]: Executing op: CustomActionSchedule(Action=Command2,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe localgroup Administrators TestUser /add,)
CustomAction Command2 returned actual error code 1 but will be translated to success due to continue marking
Even in an install started by an administrator the impersonated custom actions run without elevation. So the answer is your number 2. start the install from an elevated process with a CreateProcess-type of initiation. Having said that, it's not clear to me why you can't run the CA deferred with no impersonation because there seems to be nothing that requires the user to be an actual user as opposed to the system account. So the failure might not be elevation, and that's the issue with passing the task off to a program that isn't going to give you good error messages. So....
I've seen boilerplate code to do this kind of thing, and I believe WiX has it anyway, the Util User element, that may be the way to go.
Like Phil says, don't use net.exe to create users. Use WiX's built in features to do so (I should have found a better sample but don't have time right now):
http://wixtoolset.org/documentation/manual/v3/xsd/util/user.html
https://www.firegiant.com/wix/tutorial/com-expression-syntax-miscellanea/new-user-on-the-block/
My first instinct would be that the AlwaysInstallElevated policy would be misconfigured, but judging from the log file it is set correctly. I am rusty, but the impersonation looks like it is correctly set to "no" Phil? And the scheduling is deferred and seemingly placed right before InstallFinalize - seems OK off the top of my head.
Could it be that net.exe cannot be run properly as LocalSystem? Why then would it work when the installation is kicked off as Administrator? One would think LocalSystem had all required privileges. Isn't the current user's access token attached to the msiexec.exe process somehow? (for logging purposes or something). Or could it be a privilege that the Administrator account has that LocalSystem does not? How would that privilege apply if there is no impersonation? Did you try to manually launch net.exe as a regular user? What errors do you get when attempting to create a user when running as a regular user?
In either case I wouldn't waste my time running EXE custom actions if there is an alternative. I don't remember the last time I did. I normally use VBScript, C++ and earlier I used Installscript - with all its archaic syntax. Just switch to the built-in WiX constructs and you should be fine.

How can I stop an .exe on repair, update and delete in wix?

In my wix I use the following declaration:
<ComponentGroup Id="BinComponents" Directory="BIN">
<Component Id="BinComponent" Guid="23D229D0-06EE-49f4-80B4-6D7136500721">
<File Id="MyProjectOutput" Name="MyProject.exe" Source="MyProject\bin\MyProject.exe"/>
<ServiceControl Id="RemoveService"
Stop="both"
Remove="both"
Name="MyProject.exe"
Wait="yes" /> <!-- Stop running MyProject instances -->
</Component>
</ComponentGroup>
My Repro:
At first, I run my installation as usual. After the installation, I start my web application. An .exe appears in the task manager as usual:
I want to end this .exe on a repair, update or uninstall. So I start my .msi again and choose repair:
Now my problem: After pressing 'Repair', I expect the following dialog because of the declared ServiceControl:
But it doesn´t. Instead, the following dialog appears:
When I log the setup, the log shows the following lines:
MSI (s) (A8:DC) [10:16:28:227]: Executing op: ActionStart(Name=StopServices,Description=Stopping services,Template=Service: [1])
Action 10:16:28: StopServices. Stopping services
MSI (s) (A8:DC) [10:16:28:228]: Executing op: ProgressTotal(Total=1,Type=1,ByteEquivalent=1300000)
MSI (s) (A8:DC) [10:16:28:228]: Executing op: ServiceControl(,Name=MyProject.exe,Action=2,Wait=1,)
MSI (s) (A8:DC) [10:16:28:228]: Executing op: ActionStart(Name=DeleteServices,Description=Deleting services,Template=Service: [1])
Action 10:16:28: DeleteServices. Deleting services
MSI (s) (A8:DC) [10:16:28:228]: Executing op: ProgressTotal(Total=1,Type=1,ByteEquivalent=1300000)
MSI (s) (A8:DC) [10:16:28:229]: Executing op: ServiceControl(,Name=MyProject.exe,Action=8,Wait=1,)
MSI (s) (A8:DC) [10:16:28:229]: Executing op: ActionStart(Name=InstallFiles,Description=Copying new files,Template=File:
[1], Directory: [9], Size: [6])
[...]
MSI (s) (7C:28) [09:06:21:950]: RESTART MANAGER: Did detect that a critical application holds file[s] in use, so a reboot will be necessary.
MSI (s) (7C:28) [09:06:21:950]: Note: 1: 1610
MSI (s) (7C:28) [09:06:21:950]: Note: 1: 2205 2: 3: Error
MSI (s) (7C:28) [09:06:21:950]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1610
Next to a Repair I also have tried an Update with the same results.
Perhaps any declaration missing?
Note: When I close the MyApp.exe in the task manager, the message does not appear, so the MyApp.exe is definitely responsible for the problem.
You should post the entire log somewhere. The root cause is that a repair shouldn't routinely require files to be replaced. So if you literally installed your product, ran the exe, and then a repair needs to replace files, then the issue is not that files-in-use dialog - it's that the installed product is broken, so required files or registry entries have been removed. The application event log should have MsiInstaller entries that describe a missing component. So look at that root cause first.
After fixing that it should be very rare for a repair to need to replace files, so it may not be worth worrying about. But you could look at integrating your app with Restart Manager or using the WiX util CloseApplication.
The warning dialog that you are seeing is from "InstallValidate" standard action.
I have run into a similar issue in the past . I fixed it by making use of a single service control element instead of multiple service control elements, for the same service id.
In my case, i had multiple service control elements for the same service id.
This is as per the link at
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Upgrade-uninstall-restart-issue-td7586315.html
This did the trick for me. Numerous users have reported the same behavior, though its not officially documented.
Having a single service control element makes Restart Manager take note of the entry in the Service Control table and will prevent Restart Manager from listing the service in the RMFilesInUse dialog box or will prevent Restart Manager
from throwing up warning messages informing the user that a restart might be required.
Here is one more link
Can't start windows service with WiX
My experiments have shown me that there is definitley a link between the number of service control elements and Restart Manager
http://microsoft.public.windows.msi.narkive.com/OOuQQAsw/controlling-restart-manager-behaviour
The other option was to totally disable Restart Manager using the property RESTARTMANAGERCONTROL, In case, you disable the RestartManager, you might be prompted for reboots(you might want to test it once) and the legacy "Files in Use" mechanism kicks off. Disabling Restart Manager is a conscious decision by the concerned msi developer and at times becomes necessary.
I am not sure about how your Service Control table looks like. Just wanted to share my experience with you.
Hopefully it helps.
Regards,
Kiran Hegde

Why doesn't this silent launch work in WIX?

I have the following command running at the end of my package install for an application.
<Property Id="WixShellExecTarget" Value="[INSTALLDIR]RCR.VDS.exe" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA"
DllEntry="WixShellExec" Impersonate="no" />
I can't use [#myApplication] because I run heat on my output folder on my build server so I don't know the auto generated id of my application. Any ideas on how to silently run my application after the install?
The log file shows this for the command line section
******* CommandLine: **********
MSI (c) (30:74) [09:47:14:156]: Note: 1: 2203 2: VDSInstall.msi 3: -2147287038
MSI (c) (30:74) [09:47:14:156]: MainEngineThread is returning 2
Please see: How To: Run the Installed Application After Setup
If you want the custom action called during a silent install add:
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">SOMECONDITION</Custom>
</InstallExecuteSequence>
Note SOMECONDITION should be an expression that checks the EXE is installed and the user wants the program to be launched.
The are a copy things you can consider:
The identifier from heat.exe will be stable. So you can use the ugly identifer in your [#UglyFileId1234abcef45612345asdf] custom action.
a. You could also apply a XSLT to transform the heat output for the executable file's Id to something nicer than the ugly identifier. Depends how readable you want the launch custom action to be.
If you want the executable launched silently then you'll probably want the Quite Execution custom action instead of the Shell execute custom action that "LaunchApplication" uses.