Executing an EXE file in WiX - installation

I try to execute an EXE file from an MSI file in WiX, but I got 1603 error when doing InitializeSetup.
Action ended 12:09:54: InstallValidate. Return value 1.
Action start 12:09:54: InstallInitialize.
Action ended 12:09:54: InstallInitialize. Return value 3.
Action ended 12:09:54: INSTALL. Return value 3.
What is wrong in this WiX Script?
<Product Name='something' Id='11934d63-12d1-4792-829e-046de3bb987e'
UpgradeCode='{a101616a-365c-44a7-bfcb-fafb356c2ea1}'
Language='1033' Version='8.3.4' Manufacturer='something2'>
<Package Id='*' InstallerVersion='200' Compressed='yes' />
<Binary Id="Instalator.exe" SourceFile="d:\Instalator.exe"/>
<CustomAction Id="LaunchFile" BinaryKey="Instalator.exe" ExeCommand="" Execute='deferred' Return='asyncNoWait' Impersonate='no'/>
<InstallExecuteSequence>
<Custom Action='LaunchFile' Before='InstallFinalize'/>
</InstallExecuteSequence>
</Product>
I don't know why, but when I add:
<Directory Id='TARGETDIR' Name='SourceDir'>
<Component Id='MainExecutable' Guid='1193cd63-12d1-4792-829e-046de3bb987e'>
</Component>
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MainExecutable' />
</Feature>
after Package node -> then it works fine. I need to figure out why...

I have some other concerns about what you are doing here, but if you really need to go out of process to an EXE to complete your install, then I'd suggest using the Quiet Execution Custom Action.
You should know though that this isn't a good practice for a number of reasons. 1) It's not declarative, 2) it doesn't support rollbacks. There are others but those are the biggest IMO.
BTW, WiX isn't "scripting". Understand that and you'll understand why not to call EXE's.

Because you are running the exe as a deferred action, it runs in the context of the SYSTEM account. This error is due to the system account not having the required permissions on the file system http://support.microsoft.com/kb/834484.
It is possible to get around this using PowerShell to execute the exe using the -RunAs switch, but this is a bit nasty. It really all depends exactly what you are doing in the exe as to the best course of action. I'm with Mr. Painter, using an EXE should be the last resort.
Another option is to move the exe setup code so that it runs the first time the user runs the app.

Important note for WIX, After completion of all application installation then the .sql file or database files runs through wix or wpf or winform application.

Related

Wix : Declare or set property after ResolveSource

I try to search a file in my project. The problem is I use the var "SourceDir" and it's work fine in install with UI but no with silent install.
I found it's because SourceDir is not setted before I try to used it in silent mode.
That's why I want to set my property after the "ResolveSource" action
<Property Id='CUSTOMCONFIGFILEEXISTS'>
<DirectorySearch Id='DirSearch' Path='[SOURCEDIR]' Depth='0'>
<FileSearch Id='FileSearch' Name='EasyFolderApplicationDesktopToolbar.exe.config'/>
</DirectorySearch>
</Property>
...
<Component Id="CustomMainExecutableConfig" Guid="A952C40B-0274-4EA8-8A48-0216395455CF" Directory="INSTALLDIR" NeverOverwrite="yes">
<Condition>CUSTOMCONFIGFILEEXISTS</Condition>
<CopyFile Id="CustomEasyFolderApplicationDesktopToolbarCONFIG" SourceProperty="CUSTOMCONFIGFILEEXISTS" DestinationProperty="INSTALLDIR" />
<!--<CopyFile Id="CustomEasyFolderApplicationDesktopToolbarCONFIG" SourceProperty="CONFIGFILEEXISTS" DestinationProperty="INSTALLDIR" />-->
</Component>
I already try this, with no result :
<Property Id='CUSTOMCONFIGFILEEXISTS'>
<DirectorySearch Id='DirSearch' Path='[Temp]' Depth='0'>
<FileSearch Id='FileSearch' Name='EasyFolderApplicationDesktopToolbar.exe.config'/>
</DirectorySearch>
</Property>
<CustomAction Id='SET_CUSTOMCONFIGFILEEXISTS'
Property='Temp'
Value='[SourceDir]'/>
...
<InstallExecuteSequence>
<ResolveSource After="CostInitialize" ></ResolveSource>
<Custom Action='SET_CUSTOMCONFIGFILEEXISTS' After='ResolveSource'></Custom>
<Custom Action="AlreadyUpdated" After="FindRelatedProducts">SELFFOUND</Custom>
<Custom Action="NoDowngrade" After="FindRelatedProducts">NEWERFOUND</Custom>
<RemoveExistingProducts After="InstallExecute" />
</InstallExecuteSequence>
I already see this How do I use the SourceDir MSI property in WiX?
But I don't know how to do...
Can you help me ?
That search is ultimately an AppSearch, and in a WiX-built MSI that's the first thing that runs, so your 'CUSTOMCONFIGFILEEXISTS' property has already been processed by the search, so it's false by the time that component results in the component not being installed and the copyfile not being done. So the reason for the failure is not ResolveSource - it's because 'CUSTOMCONFIGFILEEXISTS' is being set false and you are conditioning the component and the copyfile on that false condition.
IMO you are over-thinking this. Don't bother with a search. Just pick a component relevant to the file you want to copy (don't invent a transitional component for it with a condition). Add the CopyFile to that component with [SourceDir] as the source. If the file is there it will be copied, if not then it won't be.
Don't add an unconditional ResolveSource action because it will happen every time the an installer action takes place (repair, removing features, patches, uninstall) and that is generally unnecessary. In any case I am certain you do not need a ResolveSource. There is an implicit ResolveSource at first install or it wouldn't even know where the MSI was! Just do the copyfile as I suggested.

How do I make a WiX installer force VS to install templates?

I've got a WiX installer that is meant to update VS 2010 templates after installing them. The code I'm using is as follows:
<CustomAction
Id="InstallTemplates"
ExeCommand=""[VISUALSTUDIODIR]devenv.exe" /installvstemplates"
Directory="VISUALSTUDIODIR"
Execute="commit"
Return="check"
HideTarget="no"
Impersonate="no"/>
<InstallExecuteSequence>
<Custom Action="InstallTemplates" Before="InstallFinalize"></Custom>
</InstallExecuteSequence>
In the above, VISUALSTUDIODIR refers to the correct location, and templates are correctly deployed. However, it seems that the command does not get called, so no templates are actually installed. What am I doing wrong?
WiX has built-in functionality to do that. Add a reference to WixVSExtension.dll and add the following authoring:
<CustomActionRef Id="VS2010InstallVSTemplates" />
Make sure that VISUALSTUDIODIR is an actual directory in your MSI package (it's saved in Directory table). This is a requirement for this type of custom action.
Also, try creating an installation log and search for your custom action to see what happens.

WIX public properties displayed on the UI

We have an installer created using WIX. As part of this install we would like to show the currently selected installation path. I thought this would be much easier than it is, apparently. I have tried using the a public property "INSTALLDIR" (I know we're not using Installshield, this value is a directory ID.)
<Directory Id="INSTALLDIR" Name="AcmeInc">
I can also see where INSTALLDIR gets set when running the install
MSI(EC:6C) Dir (target): Key: INSTALLDIR , Object: C:\Program Files\AcmeInc\
but when I try to show this on the UI using a Text attribute I get "...\." which doesn't even look to be a relative path.
I know there has got to be something simple I'm missing here.
Assuming you're using WiX 3.5 and the MajorUpgrade element - the following should work (I usually use APPLICATIONFOLDER instead of INSTALLDIR - but they should be interchangeable).
First, let's set ARPINSTALLOCATION as described on http://robmensching.com/blog/posts/2011/1/14/ARPINSTALLLOCATION-and-how-to-set-it-with-the-WiX-toolset
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize" />
Now lets set the selected installation folder to the previous installation folder, if one previously existed that is.
<Property Id="INSTALLDIR" Secure="yes">
<RegistrySearch Id="FindInstallLocation"
Root="HKLM"
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[WIX_UPGRADE_DETECTED]"
Name="InstallLocation"
Type="raw"
Win64="yes" />
</Property>
And during the UI sequence, we want this value to be set 'early'
<InstallUISequence>
<AppSearch After="FindRelatedProducts"/>
</InstallUISequence>

Running copied files in WiX using a custom action

I'm creating an MSI installer using WiX and I have, say, a *.bat file that I'm copying to SomeFolder2 under %temp% (something like the code snippet below...)
...
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='MyDir' Name='SomeFolder'>
<!-- %TEMP -->
<Directory Id="TempFolder" Name="TmpFolder">
<Directory Id='MyDir2' Name='SomeFolder2'>
<!-- CREATE THE %TEMP%\SomeFolder2 FOLDER -->
<Component Id='FolderComponent' Guid='{GUID}'>
<CreateFolder />
</Component>
<Component Id='CheckComponent' Guid='{GUID}'>
<File Id='mybat' Name='mybat.bat' DiskId='1' Source='.\mybat.bat' KeyPath="yes">
<Shortcut Id="mybatShcut"
Directory="ProgramMenuDir"
Name="{name}"
WorkingDirectory='INSTALLDIR'
Advertise="yes" />
</File>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
...
Now, to run this, I have two custom actions (DESTDIR is %TEMP%\SomeFolder2):
<CustomAction Id="SetPath" Property="ThePath" Value="[DESTDIR]\mybat.bat" />
<CustomAction Id="StartAction" Property="ThePath" ExeCommand="" Return="asyncNoWait" />
Then in the install sequence:
<InstallExecuteSequence>
<Custom Action="SetPath" After="{some standard MS action}">NOT REMOVE="ALL"</Custom>
<Custom Action="StartAction" Before="{some other action}">NOT REMOVE="ALL"</Custom>
...
</InstallExecuteSequence>
I've put SetPath to run after a variety of standard actions (for example, PublishProduct) while StartAction will come before another custom action.
When I run the MSI file, I look in the log and ThePath does get set with the correct path. However, when StartAction is run, I get this error:
Return value 1631.
which, according to the documentation, translate to "ERROR_CREATE_FAILED" (the Windows Installer service failed to start. Contact your support personnel). The thing is, the file did get copied to %TEMP%\SomeFolder2 (before the setting of the path and the actual exection, might I add...), but for some reason, it doesn't execute at all (if you do execute it manually or via the command prompt or whatnot, it does execute normally).
I tried putting the same file under ProgramFiles\Some_Directory_For_The_Program. The same thing happens; it gets copied there, but it doesn't execute. Why is this happening?
First off, as long as you'd like to use a file installed by your package in a custom action, you should make it deferred. That is, StartAction CA in your example must be deferred. Also, I try to use QtExec standard CA when I need to run executables from CA.
I hope this helps.

How to run a script in WiX with a custom action - simplest possible example?

Newbie WiX question: How do I
1. Copy a single-use shell script to temp along with the installer
e.g.
<Binary Id='permissions.cmd' src='permissions.cmd'/>
2. Find and run that script at the end of the install.
e.g.
<CustomAction Id='SetFolderPermissions' BinaryKey='permissions.cmd'
ExeCommand='permissions.cmd' Return='ignore'/>
<InstallExecuteSequence>
<Custom Action="SetFolderPermissions" Sequence='1'/>
</InstallExecuteSequence>
I think I have at least three problems:
I can't find permissions.cmd to run it - do I need [TEMPDIR]permissions.cmd or something?
My Sequence comes too soon, before the program is installed.
I need cmd /c permissions.cmd somewhere in here, probably near ExeCommand?
In this example permissions.cmd uses cacls.exe to add the interactive user with write permissions to the %ProgramFiles%\Vendor ACL. I could also use secureObject - that question is "How do I add the interactive user to a directory in a localized Windows"?
Here's a working example (for setting permissions, not for running a script):
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="BaseDir" Name="MyCo">
<Directory Id="INSTALLDIR" Name="MyApp" LongName="MyProd">
<!-- Create the folder, so that ACLs can be set to NetworkService -->
<Component Id="TheDestFolder" Guid="{333374B0-FFFF-4F9F-8CB1-D9737F658D51}"
DiskId="1" KeyPath="yes">
<CreateFolder Directory="INSTALLDIR">
<Permission User="NetworkService"
Extended="yes"
Delete="yes"
GenericAll="yes">
</Permission>
</CreateFolder>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
Note that this is using 'Extended="Yes"' in the Permission tag, so it's using the SecureObjects table and custom action not the LockPermissions table (see WiX docs for Permission Element). In this example the permissions applied to the MyProd directory by SecureObjects are inherited by subdirectories, which is not the case when LockPermissions is used.
I found the blog post From MSI to WiX, Part 5 - Custom actions: Introduction helpful when I wanted to understand CustomActions in WiX.
You can also find the definition of CustomAction and its attributes in CustomAction Element.
You need to do something like this
<CustomAction Id="CallCmd" Value="[SystemFolder]cmd.exe" />
<CustomAction Id="RunCmd" ExeCommand="/c permission.cmd" />
<InstallExecuteSequence>
<Custom Action="CallCmd" After="InstallInitialize" />
<Custom Action="RunCmd" After="CallCmd" />
</InstallExecuteSequence>
Have you got an example of how this is used? I mean, do use CreateFolder nested under the directory whose ACL I want to change? Or do I use CreateFolder first, separately? Is the following even close?
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id="directory0" Name="MyApp" LongName="My Application">
<Component Id="component0" DiskId="1" Guid="AABBCCDD-EEFF-1122-3344-556677889900">
<CreateFolder>
<Permission User='INTERACTIVE'
GenericRead='yes'
GenericWrite='yes'
GenericExecute='yes'
Delete='yes'
DeleteChild='yes' />
<Permission User='Administrators' GenericAll='yes' />
</CreateFolder>
<File Id="file0" Name="myapp.exe" Vital="yes" Source="myapp.exe">
<Shortcut Id="StartMenuIcon" Directory="ProgramMenuFolder" Name="MyApp" LongName="My Application" />
</File>
</Component>
<Directory Id="directory1" Name="SubDir" LongName="Sub Directory 1">
<Component Id="component1" DiskId="1" Guid="A9B4D6FD-B67A-40b1-B518-A39F1D145FF8">
etc...
etc...
etc...
</Component>
</Directory>
</Directory>
</DirectoryRef>
</Fragment>
Rather than running custom action you can try using Permission element as a child of CreateFolder element, e.g.:
<CreateFolder>
<Permission User='INTERACTIVE' GenericRead='yes' GenericWrite='yes'
GenericExecute='yes' Delete='yes' DeleteChild='yes' />
<Permission User='Administrators' GenericAll='yes' />
</CreateFolder>
Does this overwrite or just edit the ACL of the folder?
According to MSDN documentation it overwrites:
Every file, registry key, or directory that is listed in the LockPermissions Table receives an explicit security descriptor, whether it replaces an existing object or not.
I just confirmed that by running test installation on Windows 2000.
Most people tend to steer clear of the lockPermissions table as it is not additive, meaning it will overwrite your current permissions (from a managed environment perspective, this is bad). I would suggest you use a tool which supports ACL inheritance such as SUBINACL or SETACL or one of the many ACL tools.
In relation to why your earlier posts failed there is a few reasons. There are four locations where you can put your custom actions (CAs): UI, Immediate, Deferred, and Commit/Rollback.
You need your CA to set permissions in the deferred sequence, because the files are not present until midway through the deferred sequence. As such, anything prior will fail.
Your setup is in immediate (so will fail)
Your setup is at sequence of 1 (which is not possible to be deferred so will fail)
You need to add an attribute of Execute="Deferred" and change sequence from "1" to:
<Custom Action="CallCmd" Execute="Deferred" Before="InstallFinalize" />
This will ensure it's done after the files are installed, but prior to the end of the deferred phase (the desired location).
I would also suggest you call the EXE file directly and not from a batch file. The installer service will launch and the EXE file directly in the context you need. Using a batch file will launch the batch file in the correct context and potentially lose context to an undesired account while executing.

Resources