Invoking Data Protection API from within a CustomAction - wix

I am trying to run some unmanaged code from a C# ca within WIX. I have a wrapper around the CryptProtectData function, this code works fine if run from an admin prompt. I have scheduled the ca as deferred hoping it would run during the elevated session however it fails in this context.
The scheduling is as follows:
<CustomAction Id="SetCustomActionDataValue" Property="EncryptValues" Value="foo=bar;...;" />
<CustomAction Id="EncryptValues" BinaryKey="InstallerCustomAction.CA.dll" DllEntry="EncryptValues" Execute="deferred" Impersonate="no" HideTarget="no" Return="check" />
<InstallExecuteSequence>
<Custom Action="SetCustomActionDataValue" After="InstallFiles" />
<Custom Action="EncryptValues" After="SetCustomActionDataValue" />
</InstallExecuteSequence>
What needs to be done to allow something like this to run during the installer, preferably after the files and registry entries are committed to the system?

Do you have any logging in your CA? Can you confirm that your CustomActionData made it over?
One thing you might try is to wire this up as a simple console app and use PSExec to invoke a cmd.exe prompt as SYSTEM.
I've never used this API but the comment "Typically, only a user with the same logon credential as the user who encrypted the data can decrypt the data." makes me think that this might not run well as SYSTEM. This article seems to confirm that. http://www.obviex.com/samples/dpapi.aspx
FWIW, I'm not sure what you are trying to achieve but I'd consider moving it from the installer to the application if possible. Installers are generally best kept simple and reliable.

Related

Remove popups that are caused by custom actions - Wix

Newbie to wix, I am learning it. I had initially set up some custom actions for installing/ uninstalling/ rollback actions. These custom actions cause unintended popups during installation. I am trying to remove the same using SetProperty, DllEntry and BinaryKey. This is my original code:
<CustomAction Id="InstallStorageService"
Directory="ProductAppDataFolder"
ExeCommand='[ProductAppDataFolder]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)"'
Execute="deferred"
Impersonate="no"
Return="check"/>
This is what I have changed it to:
<SetProperty Id="InstallStorageService"
Value="cmd.exe /c [PRODUCTAPPDATAFOLDER]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)""
After="CostFinalize"/>
<CustomAction Id="InstallStorageService"
BinaryKey="WixCA"
Execute="deferred"
Return="check"
DllEntry="CAQuietExec"
Impersonate="yes"/>
I have done similarly for removing and for rollback actions. I do not get any errors or issues while I run the .bat file to create the msi file, but once the msi is created, I am having trouble installing it. I can share the log file if required, but there are fatal errors with not much of verbose about it.
Any help would be greatly appreciated.
You can use the Quiet Execution Custom Action pattern to invoke out of process exe's and scripts. The pattern will capture stderr and stdout to the Windows Installer log.
However it would be better to not use a .BAT as self registration (in all forms) is not a windows installer best practice. See Zataoca: Custom actions are (generally) an admission of failure.

Run ExeCommand in customAction as Administrator mode in Wix Installer

I am new to wix installer. I have developed a set-up using wix installer for my application and I need to execute a Custom Action to run a command in cmd.exe. In XP it works fine. But in Windows 8 & 7 the cmd prompt needs to be run as administrator.
I have googled and found the keywords Elevated Privileges and impersonate might help me.
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"></Package>
As you can see above, I used the InstallScope attribute set to perMachine, and I have used Impersonate="No" in the CustomAction element:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Impersonate='no'
ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
But I didn't get any changes while installating. I need the command prompt to open and run the above command in Administrator Mode.
And can anyone please tell me about these keywords "Elevated Privileges & impersonate"
<InstallExecuteSequence>
<Custom Action='comReg' After='InstallFinalize'>NOT REMOVE</Custom>
<Custom Action='comUnreg' Before='RemoveFiles'>REMOVE</Custom>
</InstallExecuteSequence>
How to do it?
The wix documentation here explains the Impersonate attribute:
This attribute specifies whether the Windows Installer, which executes as LocalSystem, should impersonate the user context of the installing user when executing this custom action. Typically the value should be 'yes', except when the custom action needs elevated privileges to apply changes to the machine.
You also need to understand the difference between deferred and immediate custom actions. See the Execute attribute on the same help page:
This attribute indicates the scheduling of the custom action. This attribute's value must be one of the following:
deferred
Indicates that the custom action runs in-script (possibly with elevated privileges).
immediate
Indicates that the custom action will run during normal processing time with user privileges. This is the default.
At present your custom action is immediate, which means it is running with user privileges. See this blog post for lots of details, but particularly:
Any immediate custom actions impersonate the invoking user. Before Windows Vista this wasn't a problem since at this point the installing administrative user had a privileged token. With the introduction of UAC in Windows Vista the default administrative token with UAC enabled is a filtered token and does not hold all privileges. Since immediate custom actions are not supposed to modify machine state - only to gather state data and schedule custom actions to run deferred - this still shouldn't be a problem. After all, at this point the generation of the installation and rollback scripts is all that should be going on.
You should never modify machine state with an immediate custom action. Use a deferred one, and keep impersonate to no, and it should work:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Execute='deferred' Impersonate='no' ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]EAWordImporter.dll" /codebase' Return='check' />
EDIT: Schedule the custom action using the InstallExecuteSequence element:
<InstallExecuteSequence>
<Custom Action='comReg' Before='InstallFinalize'/>
</InstallExecuteSequence>

'wix execute batch before uninstall with administrator

My WiX XML file installs app that contains windows-service named OLOLO_SERVICE (for example). I want to stop this service when installing/reinstalling my app.
I use CustomAction with ExeCommand='sc stop OLOLO_SERVICE'.
<CustomAction Id='EnsureThatServiceIsStopped' Directory='INSTALLLOCATION'
Impersonate="no" Execute="immediate" ExeCommand="sc
stop OLOLO_SERVICE" Return="ignore" />
Inside <InstallExecuteSequence> tag is action
<Custom Action='EnsureThatServiceIsStopped' Before='InstallValidate' />
But this doesn't works, uninstaller shows this window "For uninstallation continue you should stop following executables" (maybe not 100% correct, because in my russian Windows 7 it is written in russian).
I think that possible reasons for this are
script runs before admin rights taken (and stopping service fails because it needs admin privilegies)
script runs after validation (and validation fails when checking installed executables)
Plesae help me, I want to stop service using batch 'sc stop OLOLO_SERVICE'
PS. I decided to simplify a question: I want my WiX to execute 'sc stop OLOLO_SERVICE' with administrator privilegies and before checking for running applications
You don't need to do this in a batch file, you can use the ServiceControl element:
<ServiceControl Id="ServiceControl_OloService"
Name="OLOLO_SERVICE"
Stop="both"
Remove="uninstall"
Wait="yes" />

Running a program on uninstall

I want to run a program when my software is being un-installed, it is a simple form that should gather some feedback on why people are un-installing my software.
I found some WiX examples that works to some degree.
It works pretty fine with a standard windows program (notepad), but when I try to run my own program, it does not work. I think the problems is that the program is removed, before it has been run.
I have tried to print the logs, but they did not give me any clues of what to do.
My code so far:
<CustomAction Id="LaunchFeedBackForm"
ExeCommand="notepad.exe" Directory="INSTALLDIR"
Return="asyncWait" >REMOVE="ALL"</CustomAction>
<InstallExecuteSequence>
<Custom Action="LaunchFeedBackForm" After="InstallValidate"/>
</InstallExecuteSequence>
So I need in some way the un-install process to halt or what ever, until the user has closed the feedback form. After the form has been closed, it should continue and remove all software including the feedback form program.
The way you'd like to get user's feedback seems not that natural to me. If I understand you correctly, you'd like to show this feedback form and wait while a user fills it in, and later on continue with uninstallation, right?
To my own experience, when a user decides to uninstall software, he/she would like it to get uninstalled as quickly and clear as possible. Bringing a "must fill" form in front of them would only negatively affect the user experience. Moreover, as you can see, it is more difficult from the technical point of view. I suppose you've also thought about passing this feedback on to your side, right? Is it emailing the info entered by user? How do you ensure the email gets sent?
Alternatively, you can have this form online on a certain web page of your site and start it when the uninstall is done (NOT in progress). In this way, you don't annoy the user blocking the uninstall process.
So, I would do the following:
have a custom action that starts a browser with a URL you need
the installation program SHOULD NOT WAIT for this to complete
BTW, do not expect lots of feedback - people rarely bother spending some time to give feedback :)
If your EXE is in the MSI, try using the FileKey attribute: http://wix.sourceforge.net/manual-wix2/wix_xsd_customaction.htm
For example, if your EXE is defined like this:
<File Id="FeedbackExe" Name="FeedbackExe.exe"/>
you can use:
<CustomAction Id="LaunchFeedBackForm"
FileKey="FeedbackExe" Execute="deferred"
Return="asyncWait">REMOVE="ALL"</CustomAction>
You can also try creating an uninstall log to see what happens with the custom action:
msiexec.exe /x <ProductCode> /L*V "C:\uninstall.log"
where you use your actual ProductCode.
So I need in some way the un-install process to halt or what ever,
until the user has closed the feedback form. After the form has been
closed, it should continue and remove all software including the
feedback form program.
To do this one would set After="InstallValidate"
<InstallExecuteSequence>
<Custom Action="InstallCustomLogic" After="InstallFinalize" />
<Custom Action="UninstallCustomLogic"
After="InstallValidate" >
NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
</InstallExecuteSequence>
Set Return attribute to check so that the installer will halt until the specified executable returns.
<CustomAction Id="UninstallCustomLogic"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]\RetailConnectCustomLogic.exe uninstall"
Return="check"
/>
This is useful in the event where you need to run something located in the program directory before uninstalling the program. One could also set the attribute to ignore if it doesn't return 0

WiX uninstall - close application before Restart Manager

I have an installer done with WiX. When it's done installing, it starts an application that injects some code in the Explorer process.
Currently when I uninstall, the Restart Manager kicks in and offers to shut down my application and Explorer. Instead of that I want to close my application manually (this is done by running it again with -exit on the command line). I have a custom action that does it.
Here's what I tried so far:
<CustomAction ExeCommand="-exit" FileKey="MyApp.exe" Id="CloseMyApp" Impersonate="yes" Return="ignore" />
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" />
<Custom Action="CloseMyApp" Before="RemoveFiles" />
</InstallExecuteSequence>
This doesn't work. The action is done way after the Restart Manager session. So the Restart Manager pops up and asks to close my app and Explorer. The action runs later, but by then the app is already gone.
So then I tried this:
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallInitialize" />
<Custom Action="CloseMyApp" Before="RemoveExistingProducts" />
</InstallExecuteSequence>
This also doesn't work. The action is done too late still. I also get "warning LGHT1076 : ICE63: Some action falls between InstallInitialize and RemoveExistingProducts.".
So basically - how do I execute my custom action during uninstall and before the Restart Manager session?
I'm guessing if I use Impersonate="no" it might run at the right time, however that's not an option. That's because the new process must run for the same user as the process that has to close because it looks up its window and sends messages. That's much trickier to do if the processes belong to different users.
Any ideas?
You would need the CloseMyApp custom action to run before InstallValidate since that is when the restart manager is processed (doc). Alternatively, you could disable restart manager with MSIDISABLERMRESTART or MSIRESTARTMANAGERCONTROL Properties.