I have the following WiX excerpt which works perfectly during an install but doesn't during uninstall. I'm quite new to WiX so apologies if it's a glaring error. Can anyone see the problem?
<Property Id="APPFOLDER" >
<RegistrySearch Id="APPInstalledFolderReg"
Root="HKLM"
Key="SOFTWARE\$(var.MANUFACTURER)\One Of My Web Services"
Name="Folder"
Type="raw"
Win64="yes" />
</Property>
<CustomAction Id="SetAPPFolderProperty"
Property="APPInstalledFolder"
Value="[APPFOLDER]"
Execute="immediate"
/>
<InstallExecuteSequence>
<Custom Action="SetAPPFolderProperty"
After="AppSearch"
>APPFOLDER</Custom>
<Custom Action='MyUnregisterAction'
After='InstallInitialize'
>REMOVE="ALL"</Custom>
</InstallExecuteSequence>
During "MyUnregisterAction", the APPInstalledFolder is not set. The MsiExec Install Log reports:
Skipping action: SetAPPFolderProperty (condition is false)
I understand this means the CustomAction's not executing because the Property APPFOLDER is not set. Is the RegistrySearch not performed during Uninstall?
The Registry search is definitely performed during an uninstall.
As a matter of fact, i tried your same snippet and could get it to work.
Are you running the installation in full UI mode?
In that case, the registry search will be run in the UI mode. Probably, what is happening here is that , the value of the property APPFOLDER is not passed into the Execute sequence.
For the value of the property to be passed to the execute sequence, you need to secure the property ie. add the APPFOLDER property to SecureCustomProperties in the Property table.
Once you do this, you code snippet should start working.
In general, under normal circumstances, the values of public properties are passed from the UI sequence to the execute sequence. However, there could be lockdown conditions where the property needs to be explicitly added to the SecureCustomProperties list in the Property table for the value to propogate to the Execute sequence.
Hope this helps.
Regards,
Kiran Hegde
Related
I have a deferred custom action which fetches a property using Customactiondata, it contains the value of password that should not be displayed in the log .
Packaging tool used: WIX
Custom action written in C++
I have tried the below workarounds nothing seems to be working.
Marked the property and CA name as hidden
Hidetarget = yes in CA definition
what needs to be done?
Code:
<CustomAction Id="CASETLOGINFORRCSERVICES" Return="check" HideTarget="yes" Execute="deferred" Impersonate="no" TerminalServerAware="no" DllEntry="SetLoginForRCServices" BinaryKey="CA_Dll" />
log:
MSI (s) (7C:CC) [18:35:39:011]: Executing op: CustomActionSchedule(Action=CASETLOGINFORRCSERVICES,ActionType=3073,Source=BinaryData,Target=SetLoginForRCServices,CustomActionData=Deps###151232323)
MSI (s) (7C:B0) [18:35:39:038]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSIEB69.tmp, Entrypoint: SetLoginForRCServices
MsiHiddenProperties: There is a property you can set to hide property values from being written to the log: MsiHiddenProperties property (there are further links in there to more information on preventing confidential information in your MSI).
Custom Action: Setting the attribute HideTarget="yes" for the custom action will set the above property value for you. However this feature does not seem to hide any value you hard-code in the property table from the log - so if you set an actual value for the property in the property table you need to set the property itself hidden as well (you can set a value programmatically or via the GUI without setting it in the property table). Here are samples:
HideTarget="Yes":
<CustomAction Id="ReadProperyDeferred" HideTarget="yes" ... />
Property Hidden="yes":
<Property Id="MYPROPERTY" Hidden="yes" Secure="yes">Text</Property>
Samples: Sample WiX source here: https://github.com/glytzhkof/WiXDeferredModeSample.
Here is another sample for deferred mode - it uses the DTF class CustomActionData to easily send properties to deferred mode: https://github.com/glytzhkof/WiXDeferredModeSampleDTF
Remember to avoid custom actions if you can: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?
Sensitive Information: Here is an answer on preventing sensitive or unwanted information to make it into your MSI: How do I avoid distributing sensitive information in my MSI by accident?
Code Extract: Prefer to open the above sample. However, here is a "compressed" sequence of WiX constructs needed for deferred mode custom actions retrieving data from a set-property custom action:
<Property Id="MYPROPERTY" Hidden="yes" Secure="yes">Send this text to deferred mode</Property>
<Binary Id="CustomActions" SourceFile="$(var.CustomActionSample.TargetDir)$(var.CustomActionSample.TargetName).CA.dll" />
<CustomAction Id="SetProperty" Return="check" Property="ReadProperyDeferred" Value="[MYPROPERTY]" />
<CustomAction Id="ReadProperyDeferred" HideTarget="yes" BinaryKey="CustomActions" Execute="deferred" DllEntry="TestCustomAction" />
<InstallExecuteSequence>
<Custom Action='SetProperty' Before='InstallInitialize'></Custom>
<Custom Action='ReadProperyDeferred' Before='InstallFinalize'></Custom>
</InstallExecuteSequence>
Links:
WIX execute custom action with admin privilege
Older answer of mine on deferred mode
How can I automate testing an MSI is installable with UAC?
Add HideTarget="Yes" to the custom action.
I am using Properties to set the values of Registry entries. This is so that on install the first time I have a default value and then on upgrade the current registry value is used.
I need to have a property that sets the path to the user's local folder and to the programs folder. I know the below code is wrong but how do I do it. I think at least I want to do a Type 51 custom action but don't understand the documentation.
I believe there are three relevant parts
<InstallExecuteSequence>
<Custom Action="SetUserFolder" Before="InstallInitialize"/>
<Custom Action="SetInstallFolder" Before="InstallInitialize"/>
</InstallExecuteSequence>
Custom Action
<CustomAction Id="SetUserFolder" Property="UserFolder" Value="[%USERPROFILE]" />
<CustomAction Id="SetInstallFolder" Property="P_InstallFolder" Value="[%PROGRAMFILES]" />
The property.
<Property Id="P_MyAPPPATH" Value="[P_InstallFolder]MyApp\">
<RegistrySearch Id="S_MyAppPath" Type="raw" Root="HKCU" Key="Software\MyApp\Settings" Name="MyAppPath"/>
</Property>
<Property Id="P_MyAPPDB" Value="[UserFolder]\MyApp\MyAppData\">
<RegistrySearch Id="S_MyAPPDB" Type="raw" Root="HKCU" Key="Software\MyApp\Settings" Name="MyAppdb"/>
</Property>
As an alternative to using the properties you're defining, you might be able to use some built-in properties to better effect.
Instead of %USERPROFILE, consider LocalAppDataFolder. This will avoid your data from being copied between machines as a user roams between machines on a network domain. I'm guessing you don't need that but, if you do, use AppDataFolder and beware of the latencies involved.
Instead of %PROGRAMFILES, consider ProgramFilesFolder. This seems to be what you intend.
I'm wondering if it's possible to manually run a RemoveFolderEx element from a custom action. I'm guessing probably not but someone may know a way that I'm not aware of.
My problem is I want to run the RemoveFolderEx element but only on an true UNINSTALL however my program executes it when upgrading as I've set it to uninstall before reinstalling.
I tried it via this method
Wix: condition on property not working
however it didn't work and still ran when doing a reinstall.
The only thing I can think of is being able to manually set a RemoveFolderEx off from a custom action which I know that I run at the correct point and only on a true uninstall. Perhaps my custom action could use a c++ dll and then manually add the command to the MSI interface but if I'm going that far it might just be as well to fully write the deletion logic myself.
Thanks. Neil
EDIT: I finally got this working, here is some example wix to show what I did.
<Property Id='P.REMOVEDATAFOLDER' Secure='yes' />
<DirectoryRef Id="DATADIR">
<Component Id="C.RemoveDataFolder" Guid="myguid" KeyPath="yes">
<util:RemoveFolderEx On="uninstall" Property="P.REMOVEDATAFOLDER" />
</Component>
</DirectoryRef>
<CustomAction Id="CA.SetDataFolder" Property="P.REMOVEDATAFOLDER" Value='[DATADIR]' />
<InstallExecuteSequence>
<Custom Action="CA.SetDataFolder" Before="ValidateProductID" >(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")</Custom>
</InstallExecuteSequence>
The property P.REMOVEDATAFOLDER only gets set on a true uninstall immediately after DATADIR is read from the registry but before the CostInitialize action.
I would use the following approach. Do not condition RemoveFolderEx operation, but use a conditioned custom action to set the appropriate value for the target property.
Taking some advice from this question, the condition that denotes uninstall is REMOVE="All" AND NOT UPGRADINGPRODUCTCODE.
Something like this may work:
<Component Id="RemoveMyFolder">
<Condition> REMOVE="All" AND NOT UPGRADINGPRODUCTCODE </Condition>
<RemoveFolderEx ... />
</Component>
Ok I believe I'm following the online example in Wix3.5 for doing quiet commands yet I cannot seem to get my command to be executed quoted.
<Component Id="MapObjectsRuntime' Guid='*'>
<File Id = 'Mo23rtEXE' Name='Mo23rt.exe' Source='....' KeyPath="yes"/>
<Component>
<Property Id = "QtExecCmdLine" Value="Mo23rt.exe" />
// I've tried single & double quotes, and double double quotes around Mo23.
<CustomAction Id = "InstallMapObjects" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="check" />
<InstallExecuteSequence>
<Custom Action="InstallMapObjects" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
I do get a warning building the wix project:
The file Mo23rtEXE is not a Font, and its version is not a companion file reference.
I also need to assign command line parameters to the mo23rt.exe command but I'm first just trying to get this to work.
Lots of folks appear to be struggling with this too, as revealed by Google.
Forgot to add that running setup.exe /l*v install.log had:
MSI Doing action: InstallMapObjects
.
.
Property Change: Deleting QtExeCmdLine property. Its current value is 'Mo23rt.exe'.
CAQuitExec: Command string must begin with quoted application name.
CAQuietExec: Error 0x80070057 invalid command line property value
You schedule your custom action as immediate, but you try to run a file which should be installed by your installer. Here comes the conflict: immediate CA run BEFORE the files are installed, 'cause this happens in deferred sequence.
I would recommend you to get acquainted with Installation Phases and In-Script Execution Options for Custom Actions in Windows Installer article first.
I had tried ""mo23rt.exe"" and "'mo23rt.exe'", shame on me for not trying '"mo23rt.exe"'. Something else is still wrong but it might be what's mentioned above, or it might be I'm trying to run something that is trying to put up a status bar dialog and is not really that quiet.
I changed it to a regular custom action vice CAQuiet.
<CustomAction Id="InstallMapObjects" FileKey="Mo23rtEXE" ExeCommand="/ACDJKLM" Execute="commit"/>
followed by
<InstallExecuteSequence>
<Custom Action="InstallMapObjects" Before="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
I'm trying to simulate the InstallURL property of a VS.net install MSI... I've got to the ponit where the WIX MSI will open a browser to the download page that I want it to go to. I thought things were going great because on my test machine, the web page opened when I didn't have the MSXML6 component installed. However things went downhill when I discovered that the web page opened even when I DID have the component installed.
I'm searching for the MSXML6 component using a Property w/ a RegistrySearch. However, as best as I can tell, the registry value isn't even being evaluated, and thus it "always" looks like it isn't installed.
Here's the relevant portion of my WXS:
<Property Id="MSXML6">
<RegistrySearch Id="MSXML6Search" Root="HKCR" Key="Msxml2.DOMDocument.6.0" Type="raw" />
</Property>
<Property Id="TEST">
<RegistrySearch Id="TESTSearch" Root="HKLM" Type="raw" Name="Version" Key="SOFTWARE\Microsoft\DirectX" />
</Property>
<Property Id="cmd.exe" Value="cmd.exe" />
<CustomAction Id="OpenMSXML6Download" Property="cmd.exe" ExeCommand="/c start http://www.microsoft.com/downloads/details.aspx?FamilyID=993c0bcf-3bcf-4009-be21-27e85e1857b1" Execute="immediate" Return="check" />
<CustomAction Id="OpenMSXML6DownloadError" Error="This component requires MSXML6. =[MSXML6]=[cmd.exe]=[TEST]= A web browser has been opened to the download page. Please install MSXML6 and then re-install the connector." />
<!-- installation execution sequence -->
<InstallExecuteSequence>
<!-- wires the error dialog to the downgrade event -->
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
<!-- execution to delete old install info after upgrade-->
<RemoveExistingProducts After="InstallValidate" />
<!-- Forces MSXML6 to be pre-installed -->
<!-- <Custom Action="OpenMSXML6Download" Before="FindRelatedProducts">NOT MSXML6</Custom> -->
<Custom Action="OpenMSXML6Download" Before="FindRelatedProducts">NOT MSXML6</Custom>
<Custom Action="OpenMSXML6DownloadError" After="OpenMSXML6Download">NOT MSXML6</Custom>
</InstallExecuteSequence>
<!-- ui information for the custom actions above. -->
<InstallUISequence>
<Custom Action="PreventDowngrading" After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
<Custom Action="OpenMSXML6Download" Before="FindRelatedProducts">NOT MSXML6</Custom>
<Custom Action="OpenMSXML6DownloadError" After="OpenMSXML6Download">NOT MSXML6</Custom>
</InstallUISequence>
What this does is if MSXML6 isn't defined then it opens the web page and then prints the custom error message. Note that I'm trying to print the value of the property in the error message (I'm not sure if this is valid or not, but it seems to be.) The text that I see says "This component requires MSXML6. ==[cmd.exe]==..." so it is printing the value of the 'cmd.exe' property but not the other two... maybe that's because I define the property explicitly, I'm not sure... Anyway, I also ran the MSI with debugging on, and in the log file, I see absolutely no reference at all to the MSXML6 or the TEST properties ever being set. I've confirmed that the registry values are indeed set, although I'm not 100% sure how to handle the Msxml2 registry key, since it doesn't have any real values, only a default value. (I'm assuming that leaving off the 'Name' parameter is the right way to handle this.)
Help??
I managed to figure this one out... it was quite a simple answer. Basic issue was that the Custom Actions were executing before AppSearch, which is where the RegistrySearch properties get evaluated. See my blog post at CTICoder for details.