Creating a symbolic link in a WiX installer using relative paths - wix

I have been trying to do something like what is posted here about creating a symbolic link in a WiX installer. It explains how to make a add-on that will make a symbolic link. However that is not what I am looking for. I am trying to use somtething like this snipping
<CustomAction Id="MakeSymbolicLink"
Directory="TARGETDIR"
ExeCommand="cmd /c mklink .\linkToItem.lnk '%CommonProgramFiles(x86)%\Additional Folders\myexecutable.exe'" />
I have tried using cmd.exe instead of cmd for this and have not been successful.
I am then call the custom action like this:
<Custom Action="MakeSymbolicLink" After="InstallFinalize" />
I have tried calling this before InstallFinalize as well and I get the same behavior.
I am aiming to create the symbolic link through this setup.
The other solution I have is being able to create a shortcut however I have not been able to find much on how to do this option for places other than the start menu or the Desktop
When I run the installer after adding these lines it fails to execute them. Without the Symbolic link custom action being called I can get the installer to complete successfully.
End goal is to get a symbolic link from the common files executable to the install location of the application.
Update
I got the Symbolic link to work changed custom action now looks like:
<CustomAction Id="MakeSymbolicLink"
Directory="TARGETDIR"
ExeCommand='cmd /c mklink .\linkToItem.lnk "%CommonProgramFiles(x86)%\Additional Folders\myexecutable.exe"'
Execute="deferred"
Impersonate="no"/>
and the call to the custom action like this:
<Custom Action="MakeSymbolicLink" Before="InstallFinalize" />
But now the when I run uninstall I get the following error message: 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.

If you use something like this as your Custome action:
<CustomAction Id="MakeSymbolicLink"
Directory="TARGETDIR"
ExeCommand='cmd /c mklink .\linkToItem.lnk "%CommonProgramFiles(x86)%\Additional Folders\myexecutable.exe"'
Execute="deferred"
Impersonate="no"/>
in your InstallExecuteSequence there needs to be:
<Custom Action="MakeSymbolicLink" Before="InstallFinalize">NOT Installed</Custom>
This makes sure that this is only executed on install of your application if you want to execute this on reinstall or other options you may need to look into how to do that further
If making sure to leave zero footprint behind after a user uninstalls the application you will need to delete the symbolic link afterwards.
I solved this by doing the following:
First I created another CustomAction
<CustomAction Id="RemoveSymbolicLink"
Directory="TARGETDIR"
ExeCommand='cmd /c DEL .\linkToItem.lnk '
Execute="deferred"
Impersonate="no"/>
Then I needed another InstallExecuteSequence to execute this. However I only needed to run this on uninstall so it needed a different conditional in to do that so this one looked like:
<Custom Action="RemoveSymbolicLink" After="InstallInitialize">Installed AND NOT REINSTALL</Custom>

Related

Cmd does not work as installer custom action

I am creating an installer using WiX Toolset. I would like to backup old configuration (files with .config extension) when the checkbox is checked and then install new ones with _new appended to a name.
I have created cmd scripts to achieve that and inserted them in custom actions.
<CustomAction Id="RenameNewConfigs" Directory="INSTALLFOLDER" ExeCommand='for /r %%a in (*.config) do ren "%%~a" "%%~na_new%%~xa"' Impersonate="no" Execute="deferred" Return="ignore" />
<CustomAction Id="MoveOldConfigs" Directory="INSTALLFOLDER" ExeCommand='xcopy /SYI "..\OldConfigs" "."' Impersonate="no" Execute="deferred" Return="ignore" />
<CustomAction Id="RemoveConfigsBackup" Directory="INSTALLFOLDER" ExeCommand='rd ..\OldConfigs /S /Q' Impersonate="no" Execute="deferred" Return="ignore" />
<InstallExecuteSequence>
<Custom Action="RenameNewConfigs" After="InstallFiles">KEEP_OLD_CONFIGURATION</Custom>
<Custom Action="MoveOldConfigs" After="RenameNewConfigs">KEEP_OLD_CONFIGURATION</Custom>
<Custom Action="RemoveConfigsBackup" After="MoveOldConfigs">INSTALLED AND (NOT REMOVE="ALL")</Custom>
</InstallExecuteSequence>
During the execution (according to logs) the first and third commands produce following output:
Info 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: RenameNewConfigs, location: C:\Program Files\correct\path\, command: for /r %%a in (*.config) do ren "%%~a" "%%~na_new%%~xa"
What is wrong? Why cannot execute standard command?
There's an important difference between what can be run at the command prompt and what is actually a command. In this case, for and rd are built-in and only xcopy is it's own command. To determine this, you can run where for, where xcopy and where rd at a command prompt. In addition, Windows Installer often needs you to specify the full path to a command. This may take the form of something like [SystemFolder]xcopy.exe, but is impossible for a built-in. Instead you would need to specify something like [SystemFolder]cmd.exe /c rd ...
Note that this is not a great way to actually accomplish what you want to accomplish. Not only do command prompts popping up during an installation look bad, but the do not integrate well with logging, error reporting, or rollback. If possible, you're best off using true Windows Installer functionality (such as through the DuplicateFile and RemoveFile tables), as they are designed to handle rollback scenarios. If not, you can at least get much better integration if you write a C++ custom action dll and use it instead of exes.
You need to execute your command on executable application, in your case it will be cmd.exe.
ExeCommand='cmd.exe /c "for %a in (*.config) do ren "%~a" "%~na_new%~xa"""'
Change your code into this, and it should work :)

CustomAction run as administrator

I have created a custom action:
<CustomAction Id='AddEventLog' BinaryKey='CustomActionEventLog.dll' DllEntry='AddEventLog' Return="check" Execute="immediate"/>
Install sequence
<Custom Action="AddEventLog" Before="InstallFinalize" />
My installer does pop up and say that it needs admin rights to run. Which I grant it.
InstallPrivileges='elevated' InstallScope='perMachine' AdminImage='yes'
However when it runs the custom action it doesn't work because its not running as administrator.
I even tried adding the following to app.manifest on my custom action project dll. It didn't help.
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
I have scoured all the tutorials and forum posts I can find on this subject. Noting has worked yet.
If anyone has any better tags for this please feel free to add them I have been struggling with this all day.
Update for clarification:
While my customAction does work with EventLog I am not using http://schemas.microsoft.com/wix/UtilExtension Util:EventSource. It is a genral question can you even force a customAction to run as administrator?
To run any custom action with administrator privileges you must run the custom action during the Server portion of the installation. ie: it must be a deferred custom action. Otherwise, I think you get a consent.exe message box asking for administrator privileges.
All msi installs work in two parts, Client and Server portions of the install. The Client portion is where you see the UI and set properties that may determine where things get installed and what gets installed (they must be marked Secure for the Server portion of the install to have access to them). The Server portion is what actually puts the files on your system. This always (??) requires administrator privileges because it can be writing stuff into Program Files and other protected file locations.
These custom actions must be marked "Execute='deferred'" and must also be scheduled between the InstallaInitialize and InstallFinalize.
Also to note, if you want to use values of any properties from your installation within the custom action you need to use a separate custom action which sets a specially named property with a special format. You then get the property values in your custom action querying the CustomActionData of the session object. There are lots of examples out there you can find.
Disclaimer, I've not done this previously, and personally I'd take the other approach of using the wix extensions, but you should be able to give elevated permission to your custom actions by using deferred execution and not impersonating the current user. So in your case, Execute="immediate" is what's standing in your way.
<CustomAction Id="MyCustomAction" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
<!-- -or- -->
<CustomAction Id="MyCustomAction" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="commit" Return="check" Impersonate="no"/>
Source

WiX installer leaves empty folders for custom actions

I've created a WiX installer project and a CustomAction project. I've successfully added the MyCustomAction to the installation script and it works as it should.
However, the installer leaves empty folders in the [INSTALLFOLDER] every time the installer is executed. They're named MyCustomAction.CA.dll-, MyCustomAction.CA.dll-0, MyCustomAction.CA.dll-1 etc. Even the uninstaller won't remove them, so the amount of empty folders just get bigger.
Is there a way to prevent the folder creation? I've tried different Execute values (commit, deferred) but they don't seem to make any difference.
MyCustomAction is defined as follows:
<CustomAction Id="MyCustomAction"
Return="check"
Execute="commit"
FileKey="MyCustomAction.CA.dll"
DllEntry="MyCustomAction" />
<InstallExecuteSequence>
<Custom Action="MyCustomAction" Before="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
I found a solution to the problem: I had included the MyCustomAction.CA.dll in my product's installation files and not in its own Fragment. That caused the dll to be copied to the installation folder.
Now when the CustomActions are defined in their own Fragment the temporary folder is not created in the INSTALLFOLDER.
did you add a binary entry for them?
<Binary Id='FooBinary' SourceFile='foo.dll'/>
http://wixtoolset.org/documentation/manual/v3/wixdev/extensions/authoring_custom_actions.html

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>

How to use a file in a custom action without installing it in the InstallUISequence phase?

I would like to run an executable file with a quiet execution custom action during the InstallUISequence phase.
This executable has a text file as a parameter. I don't want that text file to be installed and I can't put it on the directory/file part as it is intented to use during the UI sequence.
How can I do that?
Here is a sample code to explain what I want:
<CustomAction Id="RunIsql_cmd" Property="RunIsql" Value=""[MYEXE]" -U [PARAM1] -i **myFileFromThePackage.txt** Execute="immediate"/>
<CustomAction Id="RunIsql" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="check" Impersonate="no"/>
How can I define myFileFromThePackage.txt ?
I've tried to define the file like this:
<Binary Id="DummyFileForInstallOnly" SourceFile="myFile.txt" />
But I can't associate the id to the CA..
Adding it in Binary table is a good approach, but you also need to extract it during install in order to use it. This can be done through a custom action which uses the Windows Installer database API.
You will also need a custom action to delete the extracted file after it has been used.