Executing a CustomAction in Wix with 'if exist' - cmd

Hi I would like to perform the following CustomAction when installing my program:
<!--Include the custom action for overwrite Client.config-->
<CustomAction Id="SetCmdLineParams" Property="QtExecCA" Value='if exist "[CURRENTDIRECTORY]\Client.config" ("xcopy" /Y "[CURRENTDIRECTORY]\Client.config" "[INSTALLFOLDER]")' Execute="immediate" />
<CustomAction Id="QtExecCA" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
<!--Include the InstallExecuteSequence for overwrite Client.config-->
<InstallExecuteSequence>
<Custom Action="SetCmdLineParams" After="CostFinalize"/>
<Custom Action="QtExecCA" Before="InstallFinalize" />
</InstallExecuteSequence>
Unfortunately this doesn't work because: CAQuietExec: Command string must begin with quoted application name.
But if I quote "if exist", then the command does not work. What can I do now?

if exist is a feature of cmd.exe. You'd need to say cmd /c first or create a .bat file and call that.
Honestly though, this is really fragile code. For one CURRENTDIR isn't always going to be what you think it is. You should write a C++ or C# custom action that uses the OriginalDatabase property to get where the MSI is running from and copy the config file from there.
Another approach I've used very successfully in the past is to write a utility that can transform a seed MSI by embedding a user provided config file into it. Now the deployment story is simplified.

Related

Rename Existing Folder using Wix

Our applications installs in a offline network that we generally don't have access to. It is also a high-availability application. We need our old application folder to still be available for use by our user, so we would like to rename the current application folder before installing the new one. That way, if we have some bugs that are no-go, we need them to be able to quickly revert to the old program.
Is this possible with Wix?
Also, we know it's not ideal, but it's what we have, so please just answer the question instead of saying "don't do that".
Just create Custom action that will start before CostFinalize and move your folder.
For example:
<InstallExecuteSequence>
<Custom Action="RenameFolder"
Before="CostFinalize"/>
</InstallExecuteSequence>
<CustomAction Id="RenameFolderCustomAction" BinaryKey="YourCustomActionDll" DllEntry="RenameFolderMethod" Execute="immediate" Impersonate="no" Return="check" />
And Your custom action will look like:
[CustomAction]
public static ActionResult RenameFolderMethod(Session session)
{
session.Log("Begin RenameFolderMethod");
Directory.Move(source, destination);
return ActionResult.Success;
}
Also, you'll need to add custom action that will copy it back in case of error or cancel. For this purpose you can use OnExit custom action.
<InstallExecuteSequence>
<Custom Action="RenameFolder" Before="CostFinalize"/>
<Custom Action="InstallationFailed" OnExit="cancel" />
<Custom Action="InstallationFailed" OnExit="error" />
</InstallExecuteSequence>
<CustomAction Id="InstallationFailed" BinaryKey="YourCustomActionDll" DllEntry="InstallationFailedMethod" Execute="immediate" Impersonate="no" Return="check" />
And action will be the same, just with reversed parameters:
[CustomAction]
public static ActionResult InstallationFailedMethod(Session session)
{
session.Log("Begin InstallationFailedMethod");
Directory.Move(destination, source);//move it back
return ActionResult.Success;
}
Also you can use properties to store source and destination paths. And you can even define them while running your msi if needed.
How to add custom actions in general

Go Program that Deletes Itself after executing

I wrote a .wxs source that creates a msi installer. The installer extracts two file in the target location one is a zip file and the other is an unzip.exe. I will trigger the unzip.exe so that it unzips the zip file and delets the zipped folder.
<File Id="ApplicationFile2" Source="unzip.exe" Vital="no" DiskId="1" Hidden="yes"/>
<!-- custom action for unzip and start services -->
<Binary Id="unzipExeId" SourceFile="unzip.exe"/>
<CustomAction Id="unzipAction" BinaryKey="unzipExeId" ExeCommand="" Execute='deferred' Return ='asyncWait' Impersonate='no'/>
<InstallExecuteSequence>
<Custom Action='unzipAction' Before='InstallFinalize'/>
</InstallExecuteSequence>
My problem is that i must delete the unzip.exe once it is executed. Can someone give me a solution to make the unzip.exe to delete itself after executing. I wrote the unzip.exe in Go.

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.

Executing an EXE file in WiX

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.

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.

Resources