I have this app, its an MSI app using WIX toolset. I faced an issue where when deployed using certain third party software, for example, COMODO one ADDT tool on windows server 2012 R2, where the app will not launch after install. The WIX config is configured to launch an executable after installing via a CustomAction.
I'm aware of "Impersonate=yes", however, Apparently when deploying the MSI, the SYSTEM user account is used which prevents the " Impersonate=yes " from working correctly.
This is how the app is being launched:
<Property Id="WixShellExecTarget" Value="[#appEXE]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
Thus the question is, is it possible to launch a "CustomAction" as the logged on user when the MSI is run from the SYSTEM user account?
The impersonate attribute is only going to have an effect for deferred custom actions. Impersonate Yes means run as the user who launched the installer and No means run as SYSTEM.
Custom actions scheduled for immediate execution (outside of the InstallInitialize..InstallFinalize block) are always going to run as the user who launched the installer.
While I'm not familiar with ADDT tool I can say that other software distribution tools such as Microsoft SCCM Server will typically launch the installer as SYSTEM so none of these ends up mattering that much. Impersonate or not you'd be running as SYSTEM.
In these scenarios it doesn't make sense to launch the application at the end of the install. You aren't in the users desktop context and no UI is possible anyways.
Our installer currently "installs" a windows service exe i.e. it just copies the file on to the users PC, but doesn't start it.
Then when our app is run, it will "install" the service many times using InstallUtil and each instance of the service will have a different service name.
So when we come to upgrade our app, we have no idea how many of these services are running and what they are called - but we do know that their service name will start with "ABCService_".
So, I created a couple of VB.NET custom actions - one called "stopServices" and one called "startServices". The first one will scan the user's PC for any windows service that starts with "ABCService_" and store its name in an XML file in the temp folder along with an attribute stating whether the service was running or not. It will then stop each of the running services.
Then the normal installation would continue - the windows service exe will be upgraded etc
The second custom action, will do the opposite - it will read the xml file and start any service that was originally running.
Now in theory (in my mind) this should work - but the problem I have is where to place these custom actions within the wix msi code. I've currently got them as:
<InstallExecuteSequence>
<Custom Action="CA_StopWindowsServices"
After="InstallInitialize" />
<Custom Action="CA_StartWindowsServices"
Before="InstallServices">
<![CDATA[NOT Installed]]>
</Custom>
</InstallExecuteSequence>
Because the custom actions alter the state of the PC, they have to be placed in the InstallExecuteSequence and Visual Studio tells me that the Stop action has to be after InstallInitialize and I thought having the start one before InstallServices might be a good place !?
BUT - this is my problem - when I run the msi; Windows complains that one of the files that needs to be upgraded (which is the windows service exe) is in use by how many instances of the service are running - which I knew would be a problem and hence why I wrote the custom actions; but I don't seem to be able to call the one that stops them before windows complains that they are in use ?!
Just thought that knowing how I defined the custom actions, might be relevent:
<CustomAction
Id="CA_StopWindowsServices"
BinaryKey="CustomActionDLL"
DllEntry="CustomActionStopServices"
Execute="deferred"
Return="check" />
<CustomAction
Id="CA_StartWindowsServices"
BinaryKey="CustomActionDLL"
DllEntry="CustomActionStartServices"
Execute="commit"
Return="check" />
Now saying all of that - I just ran my msi & when windows complained that 2 service instances were using files that needed to be replaced - I chose the first option, which is for windows to close them down and start them up at the end - which is basically what I'm trying to do :) So another question is - is it possible for me to tell windows to do this automatically - without it asking the user ? If it helps, the msi is actually run from a burn bootsrapper.
Many thanks in advance.
Cheers,
Big Chris.
Windows installer checks if files that will be replaced are in use during InstallValidate which happens before the InstallExecute sequence.
The problem is that you need elevation to stop the services which you don't have if you schedule a custom action before InstallValidate (usually).
In a bootstrapper, however, you can schedule tasks to stop the services before InstallValidate because the MSI always runs elevated from the elevated bootstrapper process that starts when you click install.
I haven't checked but adding a <ServiceControl> for the services in the MSI may automatically stop the services during the "StopServices" standard action and also avoid the FilesInUse dialog from InstallValidate. I haven't gotten around to testing this though since I already have a working solution with the bootstrapper.
So try your custom action solution but schedule your custom action to stop the services before InstallValidate.
I've just had to jump through hoops to get my application to install on Windows 8.1 and I'm concerned for my users. I'm testing the installer inside Parallels on my macbook.
First of all I had to disable SmartScreen as this just completely borked everything and wouldn't allow the installer to run at all. I'm not really happy to just tell my users to turn this off as that doesn't really make much sense.
After I jumped through that hoop Windows wouldn't allow my installer to access the C:\Program Files(x86)\ directory without administration rights. I have only one user on the machine that is in the administrators group and I was running the installer through that account.
There also wasn't a Run as Admin option in the context menu so I had to open a Command Prompt as Administrator and issue the following command:
net user administrator /active:yes
Then reboot the machine.
Since I'm a one man band operation making a free app I'm seriously short on beta testers and I can't justify getting an EV certificate to sign the installer with etc.
Seems making / distributing apps for Windows is getting harder and also trashing the user experience in the process.
What are the real options to make things better for my users?
The installer technology is WiX and I already set the following in the installer:
<Property Id="MSIUSEREALADMINDETECTION" Value="1" />
In the Product element I also already set the following:
InstallScope="perMachine"
InstallPrivileges="elevated"
I've inherited maintenance of an application that, when it runs, occasionally causes the UAC admin elevation (Do-you-wish-to-allow-this?) dialog to appear. To me, the obvious first thing to try is "switch on UAC logging", re-run the application to make the dialog appear, then find the entry in the log that says, for example, "2013-11-23-19:10:03 [MyApplication] attempted to write registry entry [MyRegistryKey]. Requires admin authorization", then take steps to resolve things so the dialog doesn't surface when the application is being used.
However, some people posted questions about UAC logging in 2008/09, in relation to Vista, and the answer was something like "UAC doesn't log, but that would be a great feature for a future release". Was UAC logging ever implemented, either in Windows 7 or as a patch release? If not, is there an alternative technique that is commonly used?
I resolved the problem eventually. Here is what happened.
1) I tried Ben's suggestion of using the sysinternals tools. The tools that seemed useful were
DependencyWalker
ProcessExplorer
ProcessMonitor
They each provide a lot of information about what is going on, and I can see that these will need to be the first port of call for many, if not most, Windows problems. However, in my case I double clicked the app and got the UAC userid/password dialog but then found that not much information had been written by the tools up to the point the dialog was surfaced.
It also looked like it would be useful to digest the contents of the Microsoft Press Windows Internals books when attempting to troubleshoot problems with UAC.
2) I tried using the Application Compatibility Toolkit, but it showed no issues with the program either on XP (where it worked) or Windows 7 (both with standard user, which surfaced the UAC dialog and admin user, which worked)
3) I then tried painstakingly recreating the app from scratch, starting with an empty project and then copying in files and settings bit by bit. At each stage, I checked whether the app would launch without surfacing the UAC dialog.
Eventually I applied a change and this caused the UAC dialog to surface. This was a VB6 app and I changed the "application title" and the "product name" in the dialog Project, Properties, Make. The previous (failing) value of each field was "ApplicationName Update". To make the app work without UAC elevation, what I had to do was remove the word "Update".
As Ian suggested above, it looks like the UAC heuristics were being applied, and to values within the exe. I see that the Windows Internals book does talk about scanning for byte sequences in the exe when deciding whether to elevate.
4) So in summary, the approach that worked for me was to reassemble the app bit by bit and see at what stage the UAC dialog is triggered. Once this happens, knowledge of the four reasons given by Ian in the previous answer become important.
5) I should point out that I have fixed the problem by removing the thing that was being flagged in the heuristics, but didn't consider the alternative suggested by Ian: "asInvoker". It could be that this is the best thing to try rather than spending time inside the (legacy) app fixing problems.
find the entry in the log that says, for example, "2013-11-23-19:10:03 [MyApplication] attempted to write registry entry [MyRegistryKey]. Requires admin authorization"
UAC does not work like that. Windows does not watch an application, and based on the activity decide that it should run elevated next time.
Windows 7 mostly behaves the same as Windows XP in this regard. If your app is running as a standard user, tries to write to:
HKLM\Software\Cotoso\Litware
your application will get an Access Denied error message.
Unless File and Registry Virtualization is enabled for buggy apps
Unfortunately, most applications are poorly written. Most applications, when run as a standard user on Windows 2000 or Windows XP, crash horribly. Since 1999, as part of the Windows Logo Requirements, Microsoft has required developers to test their applications while running as a standard user. Almost nobody ever does.
That is why, starting with Windows Vista, Microsoft added a feature that lets your buggy application think it successfully wrote to HKLM, or Program Files. If a write fails, which would have succeeded if the user was an administrator, Windows will reissue the write operation, except this time redirect it someplace that will succeed. For example:
writes to
HKLM\Software
are redirected to
HKCU\<User SID>_Classes\VirtualStore\Machine\Software
writes to
C:\Program Files
are redirected to
C:\Users\Westwell\AppData\Local\VirtualStore\Program Files
Neither of these redirection mechanisms will cause your application to be elevated on next launch. Both of these features are temporary compatibility hacks. You can inform Windows that you wrote your application correctly, opt-out of file and registry virtualzation, by adding a requestedExecutionLevel of asInvoker to your application's assembly manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="client" type="win32"/>
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Now only eliminates the side-discussion of why sometimes writes can succeed, even when the user is a standard user.
When does UAC Elevation happen
There are five reasons why an application might prompt to elevate on launch:
You manifested that your application needs to be run as an administrator.
If you app needs to be run as an administrator, and cannot perform any useful functionality without being an administrator, then you can manifest your application as requireAdministrator (rather than asInvoker):
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
If this were the case, then the application would always run as an administrator. So that's not it.
You manifested that your application be run as administrator only if the user actually is an administrator.
Applications like RegEdit can run fine as a standard user, they do not require elevation. But if the user is actually an Administrator RegEdit can prompt to elevate to the user's full admin privelages. This done by marking your application as highestAvailable (rather than asInvoker or requireAdministrator):
<description>Westwell Contoso</description>
<!-- Disable file and registry virtualization -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
If this were the case, your app would prompt for elevation for admins, but not prompt for standard users. This cannot be the cause because your application has no manifest.
Compatibilty option marked the application as Run as administrator.
The user can choose to mark an application so that it should prompt for elevation:
The state of this checkbox (and the other checkboxes) is stored in the registry:
HKCU\Software\Microsoft\WindowsNT\CurrentVersion\AppCompatFlags\Layers
and for "all users" under:
HKLM\Software\Microsoft\WindowsNT\CurrentVersion\AppCompatFlags\Layers
This option can be per-user, or per-machine. So it's possible some users will see an elevation prompt, and others will not. This could be a source of your problem.
Installer detection heuristics.
By default, Windows will attempt to recognize that an application is probably an installer (e.g. setup.exe, install.exe, update.exe) and prompt the user to elevate. This feature can be disabled through group policy, the policy name is User Account Control: Detect application installations and prompt for elevation.
The Easy Fix
The easy fix is to simply mark your application asInvoker. That will disable heuristics.
After that, it must be a compability setting on the machine (AppCompatFlags in HKCU or HKLM).
Bonus Reading
Registry Virtualization
User Account Control Data Redirection
I'm have written an msi file that offers a choice of "per-user" or "for all" installation in the UI phase, and now find that the installer fails on Vista:
if I just reuse the installer that works for XP, Vista will trigger a UAC prompt even for the "per-user" installation, making that installation pointless
if I turn off UAC in bit 3 of PID_WORDCOUNT, Vista won't invoke UAC at all anymore, so even if the user would have permission to install into the machine registry (say), the privilege raising doesn't happen, so the installation fails.
So: how can I prevent installer from invoking UAC when it isn't really needed? Alternatively, how can I programmatically request UAC even if bit 3 is set?
Unfortunately, the Windows Installer does not provide a way to create a single package that can install per-machine and per-user but only prompt for UAC on the per-machine case. The issue is that the bit that can suppress the UAC prompt is stored in the SummaryInformation stream and is not modifiable while the package is executing.
Try this reference: UAC in MSI Notes: How to Build Packages that work for both Standard User and Per-Machine?
I turned off UAC by setting the bit 3 of PID_WORDCOUNT in my MSI package. I can able to install it for "ALLUSERS" and "PER-USER", and also write in for HKLM in both the modes on VISTA machines.
Is it mandatory for you to get UAC popup for privileged user during installation?