Wix error 1721 related to CustomAction - wix

I have following CostomAction
<Binary Id='ManualsBat' SourceFile='bin\Debug\test.bat' />
<CustomAction
Id="manuals"
BinaryKey="ManualsBat"
ExeCommand="[SourceDir]Manuals "[Agent]Manuals""
Execute="immediate"
Return="check" />
test.bat contains the following lines :
#echo off
echo Hello this a test batch file
pause
mkdir %2
copy %1 %2
What it is basically intended to do is, when the installer is run, the batch file needs to get executed. The batch file has to create a new directory "[Agent]Manuals" and it has to copy all the files from [SourceDir]Manuals to [Agent]Manuals.
When I builds .wxs it does not give any error bur when I run the .msi then it complains of the following in the log files
Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: manuals, location: C:\Windows\Installer\MSI1F50.tmp, command: C:\dev\CD\Agent\pd\components\link\source\Link\Installer\WiX\WiX\bin\Debug\Manuals "D:\Cam\city\Agent\Manuals
Has anyone had experience with this kind of error. It will be great if someone can help me resolve this.

Most likely your custom action needs Administrator privileges. Try setting Execute attribute to deferred and Impersonate to no. Please note that these options require the action to be scheduled after InstallFinalize standard action.

Maybe problem in quotes. Change in ExeCommand quotes.
Try this:
<Binary Id='ManualsBat' SourceFile='bin\Debug\test.bat' />
<CustomAction
Id="manuals"
BinaryKey="ManualsBat"
ExeCommand='"[SourceDir]Manuals" "[Agent]Manuals"'
Execute="deferred"
Impersonate="no"
Return="check" />
<InstallExecuteSequence>
<Custom Action="manuals" Before="InstallFinalize">Not Installed</Custom>
</InstallExecuteSequence>

You generally need to call cmd /c foo.bat ( or command on Win9x ) to process .bat files.
However, I would never, ever do this in one of my installers. It violates the overall design on Windows Installer. MSI is a transactional, declarative programming language. Injecting out of process procedural code greatly increases the likelyhood of failure ( as you are experiencing ) and worse defeats the transactional benefits of MSI.
For example, if you create a folder and copy a file, that won't get undone during a rollback and it won't get removed during an uninstall. Instead, you should be using the built in Windows Installer features ( CreateFolder and CopyFile elements ) to achieve your goals.
On the occasion that custom actions are truely needed (in your example you are merely reinventing the wheel with an inferior solution) they should be designed using robust languages and maintaining a declarative (data driven) and transactional design while respecting the security model that MSI uses.

Related

My CustomAction is not working

I have the following CustomAction:
<CustomAction Id="CopyToSystem32" ExeCommand="[INSTALLFOLDER]copy.bat"
Directory="INSTALLFOLDER" Execute="deferred" Return="asyncWait" />
<InstallExecuteSequence>
<Custom Action="CopyToSystem32" After="InstallFiles" >NOT Installed</Custom>
</InstallExecuteSequence>
The .bat itself tries to copy some files into System32 folder. But it's not copying them. The log says the following:
CustomAction CopyToSystem32 returned actual error code 1 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (A4:DC) [15:58:46:812]: Executing op: End(Checksum=0,ProgressTotalHDWord=0,ProgressTotalLDWord=313699) 1: CopyToSystem32 2: 1603
Why isn't my CustomAction working?
Try setting Impersonate to no on your custom action
<CustomAction Id="CopyToSystem32" ExeCommand="[INSTALLFOLDER]copy.bat"
Directory="INSTALLFOLDER" Impersonate="no" Execute="deferred"
Return="asyncWait" />
that will allow your deferred custom action to run with admin privileges.
What's in the bat file? You might be asking us to debug the contents of a bat file we know nothing about. Anyway, WiX has a copyfile element that will do this without bat files, using the underlying MSI tables.
The actual error (without seeing inside the bat file) is probably the result of an assumption that the bat file is running in the same environment as if you ran it from your desktop as interactive user, but it isn't. It's being run from an msiexec.exe process that makes no assumptions about where files are located and is running with the local system account (because it's deferred).
Very few files should be copied to system32 these days. Perhaps driver files, Active X OCX files, Control Panel Applets, maybe Console Snapins, Screen Savers - all pretty unusual stuff to deploy, and I believe many of them not really necessary to deploy there at all. Are these the types of files you intend to install to system32?
Remember that there is a whole lot of protection going on in system32 via Windows File Protection on XP (replaced files reset by Windows itself) and Windows Resource Protection on Vista upwards (locked down and protected files using Windows NTFS rights). What you do there might be undone by Windows itself, so stay out of the folder if you can. And if you try to deploy runtime files from Microsoft, they should generally be deployed via Microsoft hotfixes and / or a few "still relevant" merge module runtime packages.
Deployment is not like it used to be. It is very complicated now, and many things that used to work will never work at all. It is especially important to not deploy files that are likely to be replaced by windows hotfixes. Instead, find the version of the file you depend on and set the setup to be dependent on that version or higher. See a good discussion of this here: How can I include KB2670838 in an installer with InstallShield 2013?

How to pass command line arguments in WIX Custom Action

I am using WIX Installer in which i have a custom action as below.
<CustomAction Id="ConfigureBiodentifyServer" FileKey="Biodentify.InstallUtil.exe" Execute="deferred" ExeCommand="/configurebiodentify /metadata="DefaultSetup.xml" /iskiosk="false"/databaseType="SQLServer" /sqlserver="[$(var.SqlServerName)]" /sqluser="" /sqlpw="" /domainName="[$(var.ComputerDomain)]" /domainPk="[$(var.DomainPk)]" " Impersonate="yes" Return="check" />
<InstallExecuteSequence><Custom Action="ConfigureBiodentifyServer" After="StartServices">NOT Installed And $(var.InstallType) = "SERVER" </Custom> </InstallExecuteSequence>
But the ExeCommand is giving error when i installed my Installer?
There are several levels of refactoring you should be considering. First, you are calling InstallUtil which means you are calling an Installer class custom action. This custom action should be refactored to WiX Deployment Tools Foundation (DTF) to take advantage of a better hosting pattern ( for example you can Get/Set Windows Installer properties instead of passing command line arguments ).
Also WiX has SQL extensions to handle SQL Scripts so you might be reinventing the wheel here.

WiX v3.7 - How to remove file in uninstall that was created after installation

I'm creating an installer for a program using WiX. The program creates a log file and a .dat file in the program directory during the configuration process (after complete installation). How do I tell WiX to remove these files during the uninstallation process if they are not present during the installation process?
Any suggestions would be greatly appreciated.
One way is to define the problem out of existence by installing those files. That is, create and install an empty log file and a dat file—initialized to whatever empty or default is for it.
Another way is to put RemoveFile elements under the Component element that is most closely associated with the use those files (e.g., the program exe).
Are you sure you want writable files in the same directory as the program? Usually, programs are installed so that only administrators can change them. If the program uses data that any user can change to affect all users, the data would be stored under the ALLUSERS profile. And, data that a user can change that affects only that user would be stored under that user's profile.
When data is stored that way, it is a question as to when or even whether such data should be deleted. A user might want that data preserved for the next installation of the program even if the user doesn't know how the data is persisted.
This worked for me - use custom command and delete using "del" or "rmdir"
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Forced-remove-of-folder-and-files-within-td698425.html
<Product>
<CustomAction Id="Cleanup_logfile" Directory="INSTALLFOLDER"
ExeCommand="cmd /C "del install.log""
Execute="deferred" Return="ignore" HideTarget="no" Impersonate="no" />
<InstallExecuteSequence>
<Custom Action="Cleanup_logfile" After="RemoveFiles" >
REMOVE="ALL"
</Custom>
</InstallExecuteSequence>
</Product>

Is it possible to execute a custom action in WiX that is a managed .EXE file?

I am trying to execute a custom action that was written C# (.NET 3.5) that has a dependency on a single DLL (Also C# 3.5). I have included both the .EXE and .DLL in the installation, and verified that they are being copied to the install location. However, every time I attempt to run the custom action, I get the following error:
Action start 7:21:16: InstallFinalize.
Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: UpgradeTo022, location: C:\Program Files\Test\, command: Upgrade-0.2.2.EXE
MSI (s) (CC:38) [07:21:19:061]: Product: Test -- Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: UpgradeTo022, location: C:\Program Files\Test\, command: Upgrade-0.2.2.EXE
The Custom Action is defined as follows:
<CustomAction Id="UpgradeTo022"
Directory="INSTALLLOCATION"
Impersonate="no"
Execute="deferred"
ExeCommand='Upgrade-0.2.2.EXE'>
Note: The custom action must be run with elevated privileges, thus the deferred execution and Impersonate="no" attributes.
It is scheduled as follows:
<InstallExecuteSequence>
<Custom Action="UpgradeTo022" Before="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
The files are installed as follows:
<Component Id="CMP_UpgradeCommon" Guid="8ECF5076-732E-4010-A33B-BE362D818949" Win64="yes">
<File Id="FILE_UpgradeCommonDLL"
Source="..\Upgrade\UpgradeCommon\bin\Debug\UpgradeCommon.dll" Vital="yes"/>
</Component>
I've seen some allusions to running managed EXEs as being a problem with Custom Actions and MSis, but no real definitive answers.
I have also tried just running a very simple .EXE with no dependencies as a custom action, and have had no luck there.
Being somewhat new to creating installer packages, it's very likely I'm either trying to do something that isn't supported, or missing something simple.
Thanks in advance for any pointers in figuring this out.
JT.
Unfortunately this could be a number of things. Firstly are you sure .net 3.5 is installed on the target box? On from that, can you actually run the exe fine on the target machine?
One other thing to note is that deferred actions run under the context of the system account, so if the exe requires access to a profile for any reason, this will cause it to fail. I had this very issue when trying to generate a certificate as part of my install. I was scratching my head for ages on this and in the end had to spawn PowerShell with the -RunAs switch which then ran a script to call the exe. Might be worth checking to see if the app runs fine under the system account (http://www.tech-recipes.com/rx/1288/how-to-run-applications-in-the-local-system-account-lsa/)

Deleting files and directories before installation of MSI

Our product was installed via InstallShield Setup over the years. I changed the installation to MSI (WiX) this year. Now the MSI should clean up the directory, which remains the same.
One custom action in the MSI I implemented to start the uninstallation of the old product:
<CustomAction Id="UninstallIS" Property="QtExecCA" Value=""[WindowsFolder]IsUn0407.exe" -f "[ProgramFilesFolder]\company\product\Uninst.isu"" Execute="deferred" />
<CustomAction Id="QtExecCA" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="ignore" Impersonate="no" />
After the removal of the old product there are temporary files and some subdirectories that are different from client to client and are unknown to the InstallShield Setup, so I would try to delete them via the MSI.
Keeping the UAC in mind, I think that I can't use command-line commands to do this also the 'Remove File Table' is not useful here (to much unknown files and many directories).
What is a possible way to do this?
Thank You for any help!
You can use a Deferred custom action which has Impersonate flag set to "no". This way it will run under the local system account with full privileges.
The custom action can use custom code (for example an EXE or DLL) or a command line.
Please note that deferred custom actions can be scheduled only after InstallInitialize action in InstallExecuteSequence.
As a side-note, make sure you thoroughly test it. Deleting files from the target machine is very dangerous. You never know what you may end up deleting.