Cannot run default browser from WIX installation - wix

From tutorial:
<Property Id="BROWSER">
<RegistrySearch Id='DefaultBrowser' Type='raw' Root='HKCR' Key='http\shell\open\command' />
</Property>
<CustomAction Id='LaunchBrowser' Property='BROWSER' ExeCommand='www.something.com' Return='asyncNoWait' />
<InstallExecuteSequence>
...
<Custom Action='LaunchBrowser' After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
As I can see from installation traces, property BROWSER is calculated correctly:
Property(S): BROWSER = "C:\Program Files (x86)\Internet
Explorer\iexplore.exe" -nohome
But browser is not open after installation.
MSI (s) (88:90) [18:38:30:331]: Doing action: LaunchBrowser MSI (s)
(88:90) [18:38:30:331]: Note: 1: 2205 2: 3: ActionText Action start
18:38:30: LaunchBrowser. Action ended 18:38:30: INSTALL. Return value
1. Action ended 18:38:30: LaunchBrowser. Return value 1631.
...
MSI (c) (64:6C) [18:38:30:409]: Product: WebPrintingService -- Installation completed successfully.
What could be wrong?
Windows 7.
UAC - default.
UPDATE:
As a workaround it is possible to use following code(but I am not sure that it is a good workaround):
<Property Id="BROWSER">
<RegistrySearch Id='DefaultBrowser' Type='raw' Root='HKCR' Key='http\shell\open\command' />
</Property>
<CustomAction Id="LaunchBrowser" Directory="INSTALLDIR" Impersonate="no" Execute="deferred" ExeCommand='[BROWSER] "test.html"' Return="check"/>
<InstallExecuteSequence>
<Custom Action='LaunchBrowser' Before='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>

I have not made an installer that can run the default browser after installtion but I have made an installer with WiX that launches the installed application. As far as I know, the ExeCommand property must contain the file path to an executable file. It can be either the path on your computer directly or a string property you defined containing the file path. Maybe you can tell the program wich file it should open, wich would be in your case a website.
I hope this helps.

Related

WiX CustomAction fires in UI but not Execute Sequence

We need our MSI to store the password in the registry, so users can use our installer to change connection strings, etc.
We found MsiExt for its cryptography DLL and are trying to configure the custom actions.
Our users will need to be able to install both through the UI dialogs and silently -- so we need to able to execute in both sequences.
Here is a sample of our Product.wxs
<Property Id="DB_PASSWORD" Secure="yes"/>
<Property Id="P.DB_PASSWORD">
<RegistrySearch Id="S.DB_PASSWORD" Root="HKLM" Key="SOFTWARE\$(var.Manufacturer)\$(var.ProductName)" Name="DB_PASSWORD" Type="raw" Win64="$(var.Win64)"/>
</Property>
<Component Id="c.RegistryEntries" Guid="XXXXX-XXXXX-XXXXX-XXXXX" Directory="INSTALLDIR">
<RegistryKey Root="HKLM" Key="SOFTWARE\$(var.Manufacturer)\$(var.ProductName)" Action="createAndRemoveOnUninstall">
<RegistryValue Id="R.DB_PASSWORD" Name="DB_PASSWORD" Value="[ENCRYPTED_DBPASSWORD]" Type="string" />
</RegistryKey>
</Component>
<!--For encrypting the database password on the way to the registry-->
<Binary Id="Cryptography" SourceFile="..\..\lib\msiext-1.4\CustomActions\Cryptography.dll"/>
<!--This property will receive the encrypted DB_PASSWORD that the user enters and will be encrypted-->
<Property Id="CRYPTPROTECT_DATA" Hidden="yes" />
<Property Id="CRYPTPROTECT_FLAGS" Value="CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN" />
<CustomAction Id="EncryptPassword" BinaryKey="Cryptography" DllEntry="CryptProtectDataHex" Execute="immediate" />
<CustomAction Id="SetDBUSERsPASSWORDForEncryption" Property="CRYPTPROTECT_DATA" Value="[DB_PASSWORD]" />
<Property Id="ENCRYPTED_DBPASSWORD" Hidden="yes" />
<SetProperty Id="ENCRYPTED_DBPASSWORD" Value="[CRYPTPROTECT_RESULT]" Sequence="execute" After="SetDBUSERsPASSWORDForEncryption" />
<!--This is for decrypting the registry value-->
<Property Id="CRYPTUNPROTECT_DATA" Hidden="yes" />
<Property Id="CRYPTUNPROTECT_FLAGS" Value="CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN" />
<SetProperty Id="CRYPTUNPROTECT_DATA" Value="[P.DB_PASSWORD]" Before="DecryptPassword" >NOT(DB_PASSWORD)</SetProperty>
<CustomAction Id="DecryptPassword" BinaryKey="Cryptography" DllEntry="CryptUnprotectDataHex" Execute="firstSequence" />
<CustomAction Id="SetDBUSERsDecryptedPASSWORD" Property="DB_PASSWORD" Value="[CRYPTUNPROTECT_RESULT]"/>
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<InstallUISequence>
<Custom Action="DecryptPassword" After="CostFinalize"><![CDATA[NOT(DB_PASSWORD)]]></Custom>
<Custom Action="SetDBUSERsDecryptedPASSWORD" After="DecryptPassword" ><![CDATA[NOT(DB_PASSWORD)]]></Custom>
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="SchedXmlConfig" After="InstallFiles"><![CDATA[(NOT REMOVE~="All")]]></Custom>
<Custom Action="SetDBUSERsPASSWORDForEncryption" Before="InstallInitialize" />
<Custom Action="EncryptPassword" After="SetDBUSERsPASSWORDForEncryption" />
<Custom Action="DecryptPassword" Before="InstallFiles"><![CDATA[CRYPTUNPROTECT_RESULT]]></Custom>
<Custom Action="SetDBUSERsDecryptedPASSWORD" After="DecryptPassword" ><![CDATA[CRYPTUNPROTECT_RESULT]]></Custom>
</InstallExecuteSequence>
The install log shows that the DecryptPassword is firing during the UISequence. The decryption custom action fires, then the DecryptPassword works.
Action ended 17:52:43: CostFinalize. Return value 1.
MSI (c) (CC:A8) [17:52:43:936]: Doing action: SetCRYPTUNPROTECT_DATA
Action 17:52:43: SetCRYPTUNPROTECT_DATA.
Action start 17:52:43: SetCRYPTUNPROTECT_DATA.
MSI (c) (CC:A8) [17:52:43:937]: PROPERTY CHANGE: Adding CRYPTUNPROTECT_DATA property. Its value is '**********'.
Action ended 17:52:43: SetCRYPTUNPROTECT_DATA. Return value 1.
MSI (c) (CC:A8) [17:52:43:937]: Doing action: DecryptPassword
Action 17:52:43: DecryptPassword.
Action start 17:52:43: DecryptPassword.
MSI (c) (CC:7C) [17:52:49:129]: Invoking remote custom action. DLL: C:\Users\kujotx\AppData\Local\Temp\MSI9904.tmp, Entrypoint: CryptUnprotectDataHex
MSI (c) (CC:54) [17:52:49:130]: Cloaking enabled.
MSI (c) (CC:54) [17:52:49:130]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (CC:54) [17:52:49:130]: Connected to service for CA interface.
CryptUnprotectDataHex: MSI Extensions 1.4.1114.0
MSI (c) (CC!94) [17:52:49:236]: PROPERTY CHANGE: Adding CRYPTUNPROTECT_RESULT property. Its value is 'password'.
Action ended 17:52:49: DecryptPassword. Return value 1.
MSI (c) (CC:A8) [17:52:49:238]: Doing action: SetDBUSERsDecryptedPASSWORD
Action 17:52:49: SetDBUSERsDecryptedPASSWORD.
Action start 17:52:49: SetDBUSERsDecryptedPASSWORD.
MSI (c) (CC:A8) [17:52:49:239]: PROPERTY CHANGE: Adding DB_PASSWORD property. Its value is '**********'.
Action ended 17:52:49: SetDBUSERsDecryptedPASSWORD. Return value 1.
My problem is that SetCRYPTUNPROTECT_DATA is not executing during ExecuteSequence, so DecryptPassword fails:
Action ended 17:53:47: AppSearch. Return value 1.
MSI (s) (28:1C) [17:53:47:206]: Doing action: DecryptPassword
Action 17:53:47: DecryptPassword.
Action start 17:53:47: DecryptPassword.
MSI (s) (28:98) [17:53:47:217]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI9020.tmp, Entrypoint: CryptUnprotectDataHex
CryptUnprotectDataHex: MSI Extensions 1.4.1114.0
CryptUnprotectDataHex: [CryptUnprotectDataHex] std::exception: 0x80070057 - Error in CryptUnprotectData: The parameter is incorrect.
MSI (s) (28!DC) [17:53:47:237]: PROPERTY CHANGE: Adding CA_ERROR property. Its value is '0x80070057 - Error in CryptUnprotectData: The parameter is incorrect.'.
CustomAction DecryptPassword returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 17:53:47: DecryptPassword. Return value 3.
Action ended 17:53:47: INSTALL. Return value 3.
Can you point out how to schedule our custom actions to get this to decrypt properly?
Your problem is likely due to one of the following:
The <SetProperty> element that sets the CRYPTUNPROTECT_DATA property is being conditionally run based on the value of DB_PASSWORD not being set, but we can't see from the logs that this property is indeed not set. The property action won't run if this evaluates to false.
The default setting for the Sequence attribute on the <SetProperty> element is not working correctly. Try setting the Sequence attribute to first, which will schedule it to be run in the first of either InstallUISequence or InstallExecuteSequence (will be first in silent mode). If that doesn't work, try setting it to both explicitly.
Try changing the Before attribute on the custom action for DecryptPassword in the InstallExecuteSequence to After="InstallInitialize", which is much earlier on in the install sequence than InstallFiles. This will get you behavior that is similar to running with the UI Sequence, which computes and modifies your properties and runs your actions prior to anything actually being installed.
See this page for suggested sequencing (and see relative ordering of events)

WIX Custom Action is not Executing during Upgrade

I am unable to execute custom action during Upgrade.It is giving the following error in logs.
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: CA_DFADMINWSPUPGRADE, location: E:\DealFoundrySetUp\, command: "E:\DealFoundrySetUp\PSScripts\UpdateAminWSP.bat" "Admin.wsp" "E:\DealFoundrySetUp\DFAdmin\AdminWsp\Admin.wsp"
MSI (s) (74:B4) [17:03:11:416]: Product: DealFoundry -- 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: CA_DFADMINWSPUPGRADE, location: E:\DealFoundrySetUp\, command: "E:\DealFoundrySetUp\PSScripts\UpdateAminWSP.bat" "Admin.wsp" "E:\DealFoundrySetUp\DFAdmin\AdminWsp\Admin.wsp"
<CustomAction Id="CA_DFADMINWSPUPGRADE" Impersonate="no"
ExeCommand='"[INSTALLDIR_UG]PSScripts\UpdateAminWSP.bat" "[PRO_ADMINWSPNAME_UG]" "[PRO_ADMINWSPPATH_UG]"'
Directory="INSTALLDIR" Execute="deferred" Return="check" />
INSTALLDIR_UG value i am saving in Registry and during installation and using while Upgrade
<Property Id="INSTALLDIR_UG">
<RegistrySearch Id="rsDFInstallDirectory"
Name="DFInstallDirectory"
Root="HKLM"
Key="SOFTWARE\VALUEMOMENTUM\DEALFOUNDRY\DealFoundryAdmin"
Type="raw"
Win64="yes">
</RegistrySearch>
</InstallExecuteSequence>
<Custom Action="CA_DFADMINWSPUPGRADE" After="InstallFiles">
<![CDATA[INSTALL_DFUSERMANAGEMENT=1 AND (OLDER_VERSION_FOUND)]]>
</Custom>
</InstallExecuteSequence>
Any one help me plz.
Try switching to Impersonate="yes" i think your script might not execute as Local System.

Elevated custom action before removing files

I'm trying to write an Installer for my Windows Service using WiX. My executable can register/unregister itself as a Windows Service using the command line parameters --install and --uninstall. This is what I came up with:
<CustomAction Id='InstallAsService' FileKey='CCWirelessServer.exe' ExeCommand='--install' Return='check' Impersonate='no' Execute='deferred' />
<CustomAction Id='InstallAsServiceRollback' FileKey='CCWirelessServer.exe' ExeCommand='--uninstall' Return='check' Impersonate='no' Execute='rollback' />
<CustomAction Id='UninstallAsService' FileKey='CCWirelessServer.exe' ExeCommand='--uninstall' Return='check' Impersonate='no' Execute='deferred' />
<InstallExecuteSequence>
<Custom Action='InstallAsService' After='InstallFiles' >NOT Installed</Custom>
<Custom Action='InstallAsServiceRollback' Before='InstallAsService' >NOT Installed</Custom>
<Custom Action='UninstallAsService' Before='RemoveFiles' >Installed</Custom>
</InstallExecuteSequence>
Both install and uninstall basically work. But during uninstall I get the following message:
The setup must update files or services that cannot be updated while the system is running. If you choose to continue, a reboot will be required to complete the setup.
Despite this error message, the service gets unregistered and the files are deleted without a reboot. To me this looks like the installer is checking if CCWirelessServer.exe is opened before it executes my custom action.
So my question is: How do I need to modify my install execute sequence so that this error message does no longer appear?
If you are developing for Windows Installer > 3.1 you can take a look at the MSIRESTARTMANAGERCONTROL-property to see if it it set properly or if other values would would stop displaying the message.
I could suppress the message using the following values:
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" Secure="yes" />

How to set TARGETDIR or INSTALLDIR from a registry entry?

I've got great problems setting the install dir from a value in the Windows registry which I set the last time the setup ran. This to default the path correctly. The odd thing here is that we always let the user set the installation path, even on an upgrade and if it differs from the folder of the last installation, then we don't do RemoveExistingProducts in order to let the user run several versions of the application side-by-side.
Now, I've been searching the web for a solution and I've found many suggestions but none of these actually affects my INSTALLDIR which I can see in the setup UI where I get to choose where to install.
Here's what I got at the moment:
<Property Id="PREVINSTALLDIR">
<RegistrySearch Id="PrevInstallDir"
Root="HKCU"
Key="Software\MyCompany\MyApp"
Name="InstallDir"
Type="raw" />
</Property>
<CustomAction Id="SetTargetDir" Property="TARGETDIR"
Value="[PREVINSTALLDIR]"
Execute="firstSequence" />
<InstallExecuteSequence>
<Custom Action="SetTargetDir" Before="CostFinalize"></Custom>
<RemoveExistingProducts After="InstallFinalize">PREVINSTALLDIR ~= INSTALLDIR</RemoveExistingProducts>
</InstallExecuteSequence>
Can anyone spot what I'm doing wrong here?
Note, the RemoveExistingProducts part works so PREVINSTALLDIR has been read. In the setup log I can also see this:
Action start 13:50:27: AppSearch.
AppSearch: Property: PREVINSTALLDIR, Signature: PrevInstallDir
Action ended 13:50:27: AppSearch. Return value 1.
When exiting the setup, properties are dumped into the log file and I see this:
Property(C): PREVINSTALLDIR = C:\Some\Path\MyApp
Property(C): TARGETDIR = C:\
Property(C): MyAppDir = C:\ProgramData\Microsoft\Windows\Start Menu\Programs\MyApp\
Property(C): INSTALLDIR = C:\Program Files (x86)\MiTek\MyApp\
INSTALLDIR is not affected by my wix script above, neither is TARGETDIR which I would assume would be C:\Some\Path\MyApp as well.
I've tried a bunch of things here but regardless I just can't make TARGETDIR nor INSTALLDIR change.
This worked for me:
<!-- Existing install path -->
<Property Id="EXISTINGINSTALLDIR" Secure="yes">
<RegistrySearch Id="Locate_EXISTINGINSTALLDIR" Root="HKCU" Key="Software\$(var.CompanyName)\$(var.ProductName)" Name="InstallDir" Type="directory" />
</Property>
<!-- custom action specification -->
<CustomAction Id="Set_INSTALLDIR" Execute="firstSequence" Property="INSTALLDIR" Value="[EXISTINGINSTALLDIR]" />
<InstallExecuteSequence>
<Custom Action="Set_INSTALLDIR" After="FileCost"><![CDATA[NOT Installed AND (NOT INSTALLDIR) AND EXISTINGINSTALLDIR]]></Custom>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="Set_INSTALLDIR" After="FileCost"><![CDATA[NOT Installed AND (NOT INSTALLDIR) AND EXISTINGINSTALLDIR]]></Custom>
</InstallUISequence>
Hi I managed to get my INSTALLLOCATION changed using this:
<SetDirectory Id="INSTALLLOCATION" Value="[$(var.PlatformProgramFilesFolder)]\[$(var.Manufacturer)]\[ProductName]" Sequence="both"></SetDirectory>
Value has to be a full path..hope this helps..:)

WiX: make symbolic link with UAC enabled

I want to execute a custom action in a Windows Installer (with WiX script) that makes symbolic links at the end of installation. mklink requires administrator privilege, as the installer restricts. This is what I wrote:
<CustomAction Id="mklink_cmdline" Property="QtExecCmdLine" Value='"[SystemFolder]cmd.exe" /c mklink "[SystemFolder]my_app.dll" "[INSTALLDIR]my_app.dll"' />
<CustomAction Id="mklink_exec" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="ignore" />
...
<InstallExecuteSequence>
<Custom Action="mklink_cmdline" Before="InstallFinalize">
...
</Custom>
<Custom Action="mklink_exec" After="mklink_cmdline">
...
</Custom>
...
</InstallExecuteSequence>
This works perfectly if UAC is completely disabled. However, when enabling UAC in any level, this custom action fails with
CAQuietExec: You do not have sufficient privilege to perform this operation.
even if I allowed in the consent window. I tried to change Execute to deferred, Impersonate to no, or change package's InstallPrivileges to elevated, none of them works.
Any suggestion I can bypass? Thank you!
Edit: revised code with deferred custom action
<CustomAction Id="mklink_cmdline" Property="mklink_exec" Value='"[SystemFolder]cmd.exe" /c mklink "[SystemFolder]my_app.dll" "[INSTALLDIR]my_app.dll"' />
<CustomAction Id="mklink_exec" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Impersonate="no" Return="ignore" />
...
<InstallExecuteSequence>
<Custom Action="mklink_exec" Before="InstallFinalize">
...
</Custom>
<Custom Action="mklink_cmdline" Before="mklink_exec">
...
</Custom>
...
</InstallExecuteSequence>
Does it work when ran from an administrator command prompt? I assume it does.
From what I found the msi cannot raise the UAC level which is what you need here. I had to create a setup.exe that wrapped the msi as an embedded resource and executed it. The setup.exe includes the app.manifest requesting administrator execution level which raises the UAC level appropriately:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="Setup.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</asmv1:assembly>
I may just not understand WIX, custom actions and UAC enough, but this is what I ended up doing.
Are you scheduling it between InstallInitialize and InstallFinalize when you mark it for Deferred? Your Before and after looks a little wierd:
InstallFinalize
_cmdline before InstallFinalize
_mkline_exec after _cmdline
Sounds a little nondeterministic. You might find _cmdline occurring after InstallFinalize and deferred won't work there.
Try:
InstallFinalize
_exec before InstallFinalize
_cmldline before _exec
If it's actually mklink that is requiring elevation, you might try using SysInternals junction.exe instead.
I ended up bundling elevate.exe from wintellect, deploy it to some temp folder and supply it with a path to command-line script which created all symbolic links. Than it was invoked via the custom action.
Command line file in turn has some goodness inside to detect proper program files folder. or get it from the command line, if needed.
It appears that even though WiX correctly elevates the custom action, msi (or Windows Installer) itself doesn't grant it sufficient rights to properly run mklink command.
Also note that Impersonate="yes" in the CA. I believe that's what will let msi to show elevation dialog box when it executes the action.
command line file:
cd /D %~p0
IF EXIST "%PROGRAMFILES(x86)%" SET PROGFILES=%PROGRAMFILES(x86)%
IF "%PROGFILES%".=="". SET PROGFILES=%PROGRAMFILES%
SET INSTALLPATH=%PROGFILES%\MyGreatProduct
SET DATAPATH=%PROGRAMDATA%\MyGreatProduct
IF NOT "%~1."=="." SET INSTALLPATH=%~1
IF NOT "%~2."=="." SET DATAPATH=%~2
IF EXIST "%INSTALLPATH%" mklink "%INSTALLPATH%\veryimportant.ini" "%DATAPATH%\veryimportant.ini"
in the wxs file:
<Component Directory="TempFolder" Id='Comp_Temp_Makesymlinks' Guid='47a58219-1291-4321-4321-176987154921'>
<File Id='makesymlinks_cmd' Source='makesymlinks.cmd'>
<Permission User='Everyone' GenericAll='yes' />
</File>
<File Id='elevate_exe' Source='elevate.exe'>
<Permission User='Everyone' GenericAll='yes' />
</File>
</Component>
<SetProperty Id="CA_MakeSymLinksCmd" Before="CA_MakeSymLinksCmd" Sequence="execute"
Value=""[TempFolder]\elevate.exe" "[TempFolder]\makesymlinks.cmd"" />
<CustomAction Id="CA_MakeSymLinksCmd" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="ignore" Impersonate="yes" />
<InstallExecuteSequence>
<Custom Action="CA_MakeSymLinksCmd" Before="InstallFinalize"><![CDATA[NOT Installed AND VersionNT >= 600 ]]></Custom>
</InstallExecuteSequence>