Add user before running custom action in Wix - windows

We have an install script in Wix, which contains Fragments, components and some custom actions:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util='http://schemas.microsoft.com/wix/UtilExtension' >
<Product Id="*" Name="Installation" Language="1033" Version="1.0.0.0">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine">
</Package>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" />
<Feature Id="ProductFeature" Title="MyInstallation" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="MyComponents" />
</Feature>
<util:Group Id="Users" Name="Users"/>
<CustomAction Id="InstallMyService"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]bin\my-service.bat install"
Execute="deferred"
Impersonate="no"
Return="check"/>
<CustomAction Id="SetEnvironmentVariable" BinaryKey="ActionLib" DllEntry="SetEnvironmentVariableForNewUser" />
<Binary Id='ActionLib' SourceFile='..\InstallerActionLibrary\bin\Release\InstallerActionLibrary.CA.dll' />
<CustomAction Id="StartMyService"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]bin\my-service.bat start"
Execute="deferred"
Impersonate="no"
Return="asyncWait"/>
<InstallExecuteSequence>
<Custom Action="InstallMyService" After="InstallFiles"/>
<Custom Action="SetEnvironmentVariable" After="InstallMyService"/>
<Custom Action="StartMyService" After="SetEnvironmentVariable"/>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CommonAppDataFolder">
<Directory Id="Company" Name="Company">
<Directory Id="App" Name="Product">
<Directory Id="INSTALLFOLDER" Name="Service" />
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="NewUser" Guid="{12345678-ABCD-1234-ABCD-987654321FED}">
<CreateFolder />
<util:User Id="CIUSER" CreateUser="yes" UpdateIfExists="no" Name="SERVICEUSER" PasswordNeverExpires="yes" Password="********">
<util:GroupRef Id="Users" />
</util:User>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
However, one of the Custom Actions, SetEnvironmentVariable, needs to be run after the user has been set up, in the fragment at the bottom of the file. And this does not happen. SetEnvironmentVariable fails because it cannot find the user.
The sequence, given in InstallExecuteSequence begins after InstallFiles has occurred. I have tried to find a more appropriate place to start the sequence, using the list given here. I have tried PublishProduct and the result is the same.
Is there any way to get the user added before the custom action runs?

The suggestion from #zett42 was a good one. However, it still did not solve the problem.
The solution was the incorrect use of Execute="deferred". The execution of all the custom actions should have been set as:
Execute="commit"
From the Wix Documentation:
commit
Indicates that the custom action will run after successful completion of the installation script (at the end of the installation).
Changed the Execute type to commit and it worked.

I have no direct answer, but one that should help you to figure it out by yourself:
Open the MSI package using a tool like Orca (included in Win SDK) or InstEd (my personal preference).
Navigate to the InstallExecuteSequence table.
Lookup the record of the WiX custom action that creates the user and copy the Action identifier of that record.
Use that identifier for the After attribute of the element <Custom Action="SetEnvironmentVariable"/>.

I agree with #zett42.
There are some wix standard actions which should be checked in msi editor,
if you need to know when exactly they are being called. We normally don`t get much documentation for such actions.
Check if your msi has SchedSecureObjects_x64 or SchedSecureObjects custom action in msi. Schedule SetEnvironmentVariable custom action after that action.

Related

WiX setup creating a Registry key doesn't work when also using CustomActions

I have issues understanding the order of operation of the WiX setup.
When trying to create a Registry key to add a menu entry to Windows Explorer context menu and simultaniously
using CustomActions the Registry key will not be added.
If I however only try to register the key, it works (any CustomAction code is commented out).
In my Product.wxs I have set elevated priviliges with
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"/>.
In my <Feature> I have
<ComponentRef Id="RegistryEntries"/> referenced.
This is the code for creating the registry key
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="RegistryEntries" Guid="*">
<RegistryKey Root="HKCR"
Key="Excel.CSV\shell\Use MyConverter\command"
ForceCreateOnInstall="yes"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Value="[INSTALLLOCATION]$(var.SolutionName).exe %1"
KeyPath="yes"/>
</RegistryKey>
</Component>
<Directory Id="ProgramFilesFolder">
<Directory Id="HSZLG" Name="MyConverter">
<Directory Id="INSTALLLOCATION" Name="$(var.SolutionName)" />
</Directory>
</Directory>
<!--<Directory Id="ProgramMenuFolder">
<Directory Id="Shortcuts" Name="MyConverter" />
</Directory>-->
</Directory>
</Fragment>
Now Im also using the following Custom Actions:
<CustomAction Id="UnregisterImportFormat" BinaryKey="WixCustomAction" DllEntry="UnregisterImportDefinition" Execute="deferred" Impersonate="no" Return="check" />
<CustomAction Id="PropertiesForUnregisterImportFormat" Property="UnregisterImportFormat" Return="check"
Value="app=AB;key=10000P1000" />
And call them in the <InstallSequence> like this:
<InstallExecuteSequence>
<Custom Action="PropertiesForRegisterImportFormat" Before="RegisterImportFormat" />
<Custom Action="RegisterImportFormat" Before="InstallFinalize">(NOT Installed) OR REINSTALL</Custom>
<Custom Action="PropertiesForUnregisterImportFormat" Before="UnregisterImportFormat" />
<Custom Action="UnregisterImportFormat" Before="InstallFinalize">REMOVE</Custom>
</InstallExecuteSequence>
It'd be gladly appreciated if someone can point out what I am doing wrong here.
There are difficulties with (deferred) custom actions running without impersonation as well as the HKCR key because HKCR isn't an actual registry location - it's a merge of the interactive user and HKEY_LOCAL_MACHINE\Software\Classes. This goes into detail:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
and the custom action code is running with the system account (deferred, no impersonation) which is adding more confusion about which registry key you're creating. As that MSDN note says:
"To change the settings for the interactive user, store the changes under HKEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT"
and I assume your code is attempting to use HKCR. Windows Installer is preferred for writing these registry entries because "it just works". Code running with the system account writing to HKCR is unreliable, so if you really must use code (and you shouldn't) then try HKEY_LOCAL_MACHINE\Software\Classes.

Migrate Wix Project to version 4.0

I recently ugraded Wix to Version 4.0.
After updating the namespaces Visual Studio (2015) won't recognize these new ones.
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Product Id="*" Name="_any_name" Language="1033" Version="1.0.0.0" Manufacturer="Anyone" UpgradeCode="8c568038-54cf-43ff-aa2c-581f4dd0aea0" Codepage="1252">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="_any_title" Level="1">
<ComponentGroupRef Id="group_ProductComponents" />
</Feature>
<Property Id="pro_SetupExe" Value="INSTALLFOLDER" />
<CustomAction Id="ca_LaunchSetupExe" Property="pro_SetupExe" ExeCommand="/FORCE_HIDE_FIRST_RUN /UNATTENDED_INSTALL /AUTOACCEPT_ALL /FORCE_CLOSE_WHEN_DONE /ON_REBOOT_MESSAGE:”NO”" Execute="commit" />
<CustomAction Id="ca_SetSetupPath" Property="pro_SetupExe" Value="[INSTALLFOLDER]x64ATIDriver\setup.exe" />
<InstallExecuteSequence>
<Custom Action="ca_SetSetupPath" Before="ca_LaunchSetupExe" />
<Custom Action="ca_LaunchSetupExe" Before="InstallFinalize" />
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="TempFolder">
<Directory Id="INSTALLFOLDER" />
</Directory>
</Directory>
</Fragment>
</Wix>
The Wix element has an incorrect namespace of 'http://wixtoolset.org/schemas/v4/wxs'. Please make the Wix element look like the following: Wix xmlns = "http://schemas.microsoft.com/wix/2006/wi"
I founde these: Migrate Wix Project to v4.0 instructions
But I don't get what this means:
Fix: Explicitly set absent Id attributes on File element to the Name attribute or filename from the Source attribute.
So currently I just have the kind of "crashed" project and can't build.
I'd really appreciate some help.
regards Muffex
The namespace error makes it sound like the project is still being built by WiX v3. Also, that migrate to v4 page that you found is for the WixCop tool which automates everything you found there. It's in the bin directory of the WiX installation directory.

Non-installing MSI file

I am currently working on a tool for system administrators that can be used to update all clients of a Windows AD. It needs to work with Group Policy and SMS for the purpose of doing mass-updating. Therefore I need the tool to result in a MSI file.
Is it possible to create a MSI file that does not install anything but instead only does a custom action (ie. run a script or exe-file).
Best Regards Jakob Simon-Gaarde
Yes, it is possible. Shameful, but, possible.
You can make a square peg fit in a round hole but you lose all of the intended benefits.
FWIW, SMS is now called SCCM and it can call EXE commands.
Found a hackish way to solve my problem:
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product
Name='MVLicense Updater' Id='f8fc0a30-c138-1fe2-838b-0845200c9a66'
UpgradeCode='00ca86a0-c889-12e2-8f8b-0800200c9a66'
Language='1033' Version='1.0.0.0' Manufacturer='My Company'>
<Package Id='*' InstallerVersion='200' Compressed='yes' />
<Media Id='1' Cabinet='my.cab' EmbedCab='yes' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder'>
<Directory Id='INSTALLDIR' Name='My-Updater'>
<Component Id='Readme' Guid='68fef080-c87b-34e2-8889-0824200c9a66'>
<File Id='ReadmeTXT' Name='readme.txt' Source='readme.txt' Vital='no' />
<RemoveFolder Id="INSTALLDIR" On="uninstall" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='Complete' Level="1">
<ComponentRef Id='Readme' />
</Feature>
<CustomAction Id="ForceError" Error="1602"/>
<CustomAction Id="RunMyUpdater" BinaryKey="MyUpdaterExe" ExeCommand="dummy" Return="check"/>
<InstallExecuteSequence>
<Custom Action='RunMyUpdater' After='InstallInitialize'></Custom>
<Custom Action="ForceError" After="RunMvlupdate"></Custom>
</InstallExecuteSequence>
<AdminExecuteSequence>
<Custom Action='RunMyUpdater' After='InstallInitialize'></Custom>
<Custom Action="ForceError" After="RunMyUpdate"></Custom>
</AdminExecuteSequence>
<Binary Id="MyUpdaterExe" SourceFile="dist\myupdater.exe" />
<UI>
<Error Id="1602">We have a problem</Error>
</UI>
</Product>
</Wix>
This does the job of running my executable that does some configuration stuff based on calling an internet service and then rolls back the installation because I force an error to occure.

Can't get Wix custom action to work in Votive/VS2010

Help! I need to execute a managed custom action in my Wix 3.5 setup project and no matter what I've tried I can't get it to work.
I'm using the Votive integration in Visual Studio 2010. My Wix Product.wxs file is basically unchanged from the visual studio template except a few text changes:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="666ffc07-90b2-4608-a9f0-a0cc879f2ad0" Name="Product Name" Language="1033" Version="5.5.0002" Manufacturer="TiGra Astronomy" UpgradeCode="d17a5991-b404-4095-9e93-08d2db984cfd">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLLOCATION" Name="Directory Name">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent" Guid="3ea5ade7-9b7b-40da-9e83-13e066a000ef"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
</Directory>
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="ASCOM Driver" Level="1">
<!-- TODO: Remove the comments around this ComponentRef element and the Component above in order to add resources to this installer. -->
<!-- <ComponentRef Id="ProductComponent" /> -->
<!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
<ComponentGroupRef Id="Product.Generated" />
</Feature>
</Product>
I have set a reference to my managed custom action project, set the HARVEST property to true. The project is called WIX.CustomActions and produces WIX.CustomActions.dll and WIX.CustomActions.CA.dll
I see that Wix is processing the reference during build and the WIX.CustomActions.dll assembly shows up in the Binary table in the final setup project, but the WIX.CustomActions.CA.dll does not.
I have a CustomActions.wxs that should package and invoke the custom action:
<?xml version="1.0" encoding="UTF-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Binary Id="DriverRegistrationCA" SourceFile="$(var.WIX.CustomActions.TargetDir)\$(var.WIX.CustomActions.TargetName).CA.dll" />
<CustomAction Id="RegisterDriver" BinaryKey="DriverRegistrationCA" DllEntry="RegisterAscomDriver" Execute="deferred" Return="check" />
<CustomAction Id="UnregisterDriver" BinaryKey="DriverRegistrationCA" DllEntry="UnregisterAscomDriver" Execute="immediate" Return="check" />
<InstallExecuteSequence>
<Custom Action="RegisterDriver" After="InstallFinalize" />
<Custom Action="UnregisterDriver" Before="RemoveFiles" />
</InstallExecuteSequence>
</Fragment>
</Wix>
I've looked at various 'howto' sources on the interweb and they are at best confusing, with contradictory advice. As I understand it, the WIX.CustomActions.CA.dll file is an unmanaged dll that loads the .NET framework and passes control to the 'real' managed custom action. However, the WIX.CustomActions.CA.dll does not get packaged in my MSI file. I've followed examples as best I can but I can't see what's wrong.
Please, has anyone got this working in Votive? Can you give me an actual working example?
You need a reference (e.g., CustomActionRef) from your product to the fragment; otherwise, it's discarded by the smart linker.
Following on from Bob Arnson's suggestion, I added the following two lines near the top of my Product.wxs file:
<CustomActionRef Id="RegisterDriver"/>
<CustomActionRef Id="UnregisterDriver"/>
That seems to have done the trick. Orca now shows that I have a Binary table, containing my CA dll, and a CustomAction entry in InstallExecuteSequence.
None of the examples I found on the web mentioned this requirement. I guess people were just recycling received wisdom with little or no understanding. So here is the answer, thanks to Bob!

Launch after install, with no UI?

How do I launch my application after install with no UI (or in quiet mode)? Thanks!
I had a installer with UI which has an option to run after install. Now I want my application to updates itself by downloading and running the new version of installer in quiet mode, but after updating done, it won't launch again.
From the msdn topic on sequencing custom actions:
As in the case of standard actions,
custom actions that are scheduled in
the InstallUISequence or
AdminUISequence run only if the
internal user interface is set to the
full level.
So I guess your custom action is scheduled in a UI sequence, not in InstallExecuteSequence. Try scheduling your custom action in the InstallExecuteSequence like this:
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFiles'/>
</InstallExecuteSequence>
where "LaunchApplication" should be replaced by the Id of your CustomAction element.
edit: I looked at the instructions that you followed, and I don't see the custom action for launching the application being scheduled in any sequence. It is only triggered from a UI action (clicking the Finish button). This explains why it is never executed during a silent install.
edit: full sample (it's a bit sloppy as it also tries to execute the custom action on uninstall, repair etc. but for some reason I couldn't get the "NOT Installed" condition to work)
<?xml version='1.0' encoding='utf-8'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product
Name='ProductName'
Id='*'
Language='1033'
Version='0.0.1'
Manufacturer='ManufacturerName' >
<Package
Keywords='Installer'
Description='Launch application demo'
Manufacturer='ManufactererName'
InstallerVersion='100'
Languages='1033'
Compressed='yes'
SummaryCodepage='1252'/>
<Media Id='1' Cabinet='test.cab' EmbedCab='yes'/>
<Directory Id='TARGETDIR' Name="SourceDir">
<Directory Id='ProgramFilesFolder'>
<Directory Id='TestFolder' Name='Test' >
<Component Id="ExeComponent" Guid="*">
<File Id="ExeFile" Source="c:\windows\notepad.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='Complete'
Display='expand'
Level='1'
Title='Test'
Description='Test'>
<ComponentRef Id="ExeComponent" />
</Feature>
<InstallExecuteSequence>
<Custom Action='LaunchInstalledExe' After='InstallFinalize'/>
</InstallExecuteSequence>
<CustomAction Id="LaunchInstalledExe"
FileKey="ExeFile"
ExeCommand=""
Execute="immediate"
Impersonate="yes"
Return="asyncNoWait" />
</Product>
</Wix>
In my final solution I used two properties, one for UI (LAUNCH_APP_ON_EXIT), one for command line arguments (UPDATING_AUTOMATICALLY).
I have to do this because if I run the CustomAction after InstallFinalize in full UI mode, the application would start before you click the "Finish" button.
Now I can call setup.exe /qn UPDATING_AUTOMATICALLY=1 in my program to update.
Here is it all:
<Property Id="LAUNCH_APP_ON_EXIT" Value="1" />
<Property Id="UPDATING_AUTOMATICALLY" Value ="0" />
<CustomAction Id="LaunchApplication" FileKey="mainExecutableFile" ExeCommand="" Execute="immediate" Impersonate="yes" Return="asyncNoWait" />
<UI>
<!-- explainations: http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/ -->
<UIRef Id="MyWixUI_InstallDir" />
<UIRef Id="WixUI_ErrorProgressText"/>
<Publish Dialog="MyExitDialog" Control="Finish" Order="1" Event="DoAction" Value="LaunchApplication">LAUNCH_APP_ON_EXIT</Publish>
</UI>
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFinalize'>UPDATING_AUTOMATICALLY = 1</Custom>
</InstallExecuteSequence>
I would assume that you are launching your app from a custom action, which is triggered through a property bound to the checkbox. If that is the case, you can try specifying that property as a command line argument to setup.exe. Say, if your custom action is bound to the MSI property LAUNCH_NEW_VERSION, you can call setup.exe like this:
setup.exe /q LAUNCH_NEW_VERSION=1
The standard setup bootstrapper should pass that property/value to the MSI engine. If it doesn't, you might consider invoking the .msi directly instead of calling the bootstrapper exe to run your installer.
This is the approach I took.
<Property Id="WixShellExecTarget" Value="[#(the id of your exe here)]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
This will execute which ever file id you enter in the Value. The [# ] is needed. I used this and ran it via the UI but you should be able to call this custom action anywhere and it work.

Resources