Elevated installer with elevated custom action does not elevate executable - c#

I have an installer with InstallPrivileges="elevated". I include inside the file table an app.EXE
<Component Id="myapp" Guid="*">
<File Id="myapp" Source="myapp.exe"/>
</Component>
using these CA to run it in an elevcated state:
<CustomAction Id="SetProp" Property="Launch" Value =""[INSTALLDIR]myapp.exe""/>
<CustomAction Id="Launch" BinaryKey="WixCA" DllEntry="CAQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
scheduled like this:
<Custom Action="SetProp" Before="Launch">NOT Installed</Custom>
<Custom Action="Launch" Before="InstallFinalize">NOT Installed</Custom>
but according to Uachelper class (c#) and the missing result this process is not elevated BUT verbose log and myapp.exe log shows no error.
I also tried to use a type 2 custom action (binarykey etc.), a type 18 custom action (filekey etc.) and to include an app.manifest into myapp.exe with requiredadministrator.
nothing worked to elevate myapp.exe.. during installation.
Workaround I found is to start myapp.exe manually after installation completed (go to [INSTALLDIR] and doubleclick myapp.exe, will prompt uac etc.) but I want to avoid that.
I also thought about trying to use runas but am not sure if this would work or if this is feasible.
All of this is based on http://wixtoolset.org/documentation/manual/v3/customactions/qtexec.html , https://stackoverflow.com/a/10028939/4096653 and many more questions here on SO.
What am I missing or what else can I try?

By default a custom action will be elevated only if it is deferred, not impersonated, and sequenced between InstallInitialize and InstallFinalize, and if it's a per machine install, and then it will run elevated with the system account. Whether it will actually work or not depends on whether the code is prepared to deal with being aware that it's not running as the interactive user with access to HKCU, user profile items like PersonalFolder, and the code knows where its data is. When a custom action executable gets fired off it is via the CreateProcess() type of call (NOT a shell execute call) and so there is no UAC dialog/manifest checking stuff going on. So your WiX posted looks correct if you are deferred and before InstallFinalize. I have no idea what a UACHelper class thinks if are running as system and elevated. ProcessMonitor/Explorer might tell you what your rights/tokens are.
It should work if you create an impersonated launcher custom action that does an explicit Shell Execute of your exe, because that behaves like a run from Explorer by the interactive user. It will run the app which will then ask for elevation as long as the user doing the install is admin. In code that's something like ProcessStartInfo.UseShellExecute=true, ShellExecute() Win32.
If you need an impersonated CA to be elevated the MSI needs to be running as administrator or started from a program with an elevation manifest that then runs the MSI.
You'll see lots of advice (I hope) saying you should arrange to run this automatically the first time your app runs, just have it launched and remember whether that it has been run. Running as elevated user from an MSI is too complicated unless you have an elevated launching bootstrapper.

I assume you want this to run in Execute sequence and have scheduled your custom actions in InstallExecuteSequence
It might be so that your app is not able to run as Local system user so try to switch the Impersonate to yes Impersonate="Yes"

Related

msiexec uninstall from c# fails to stop service

I have a service that runs and accepts remote commands. I am trying to send a remote command to uninstall. This works and executes the msiexec. The msiexec gets to the point where it tries to stop the service and then hangs and eventually fails saying no privileges to stop the service.
If I run the same command from a command window it works fine.
I have tried this running the service as local system (with admin privs) as well as administrator (I enabled the administrator account)
I just can't seem to figure out why I am getting permission errors stopping the service running the msiexec
added information
We have a single service - it does required work and sleeps periodically
the service typically runs as local system
we have the installer set using custom actions - and all cases work fine - installing and uninstalling from command line - but running msiexec uninstaller initiated within the C# code has this issue
When a remote request is made to uninstall the desire is to remove the service, registry entries, and files on disk
The request is handled by the running service - it goes to the registry, finds the product entry and retrieves the uninstall command
when the uninstall is performed I use C# process and include in the StartInfo parameters the program name, arguments, and verb (defined as run as) - among other parameters
the uninstaller starts properly, does some actions, and then gets to the point of stopping the service
stopping the service sits until it times out after which it writes in the uninstall log that there may not be sufficient privileges to stop the service
The note from Quercus triggered the solution to my problem. It turns out changing to not run the uninstall as a child of the service allowed the uninstaller to perform the msiexec without issue. To accomplish this I had to change UseShellExecute from false to true.

Run unelevated custom action from a WiX elevated installer

I'm trying to figure out how to run a custom action from an elevated WiX installation setup program. The msi file generated by WiX is executed by DotNetInstaller.
In WiX I have a Package section with InstallScope set to perMachine and this custom action:
<CustomAction Id='RegisterPlugin' FileKey='RegisterPluginExe' ExeCommand='' Return='asyncNoWait' Impersonate='yes' />
<InstallExecuteSequence>
<Custom Action='RegisterPlugin' After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
Impersonate set to yes should run the action exe as the user who run the DNI bootstrapper.
The custom action should read a file in the user AppData directory, using the value obtained by System.Windows.Forms.Application.LocalUserAppDataPath, but the directory used is wrong because is the one of the Administrator user.
I tried to use a manifest to run DNI unelevated, but the problem remains. If I run the msi directly, it correctly does some registry operations which require administration rights, while the custom action runs as expected.
Edit:
Looking at the task manager I can see that, if the msi is executed from DNI, the user becomes Administrator when the msi is started. If I run the msi directly, the user is always the same, even during the files installation on the system directory. It seems that in this case what change is not the identity, but the privileges.
Any ideas?
Thanks,
Stenio

Loss of admin privileges when Java program calls C# program to write to %ProgramData%

The scenario:
I have a Java based installer.
The Java based installer calls a C# program, whose job is to create a shortcut.
The shortcut location depends on if the installer is running as administrator or as a regular user. When running as admin, I'm trying to create a shortcut to "%ALLUSERSPROFILE%\Desktop", else I write to "%USERPROFILE%\Desktop".
My impression is that the issue seems to be a loss of administrative privilege when my Java program calls my C# shortcut maker program.
Notes:
I run my Java based installer as administrator (right click, run as administrator).
I'm able to verify the installer is running with administrator privileged because I can read registry keys that require administrative privilege.
I'm calling my C# program via 'Process process = Runtime.getRuntime().exec(command);'
When running the command manually through an administrative command prompt, the command works fine. (When outputting to "%ALLUSERSPROFILE%\Desktop")
When running the the same command manually, from a normal command prompt, I get System.UnauthorizedAccessException. (Which is to be expected). The program crashes in a similar was that it does when run from the installer.
The Exception:
Unhandled Exception: System.UnauthorizedAccessException: Access is
denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) at
IWshRuntimeLibrary.IWshShortcut.Save()
Any thoughts on what I'm missing? The installer needs to be flexible to run as both a normal user and as an administrator. How can I ensure this behavior?
Update 1
I attached a debugger to the C# program at runtime. It is throwing a:
DirectoryNoFoundException was unhandled
The system cannot find the path specified. (Exception from HRESULT: 0x80070003)
I added "mkdir" commands before my shortcutmaker commands. The mkdir commands, just ensure that the directories exist before trying to write to them.
Rebuilt the installer, ran it and when trying to mkdir "%ALLUSERSPROFILE%\Desktop", java throws an exception of
java.io.IOException: Cannot run program "mkdir": CreateProcess error=2, The system cannot find the file specified
java.io.IOException: Cannot run program "mkdir": CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
At this point, it looks like my process isn't getting admin access
Process process = Runtime.getRuntime().exec(command);
I'm going to see if I can find anything else.
Update 2
The following gave me some info that I tried: Enterprise Logging not translating environment variables in XML Trace Listener fileName specification
It suggested that %ALLUSERSPROFILE% was not getting translated.
Instead of %ALLUSERSPROFILE%, I got the environment variable values via:
String allUsersProfile = System.getenv("ALLUSERSPROFILE");
String userProfile = System.getenv("USERPROFILE");
I was then able to supply the actual values to the C# program. But I'm still having issues.
From a admin console I can navigate to "c:\ProgramData\Start Menu", but if I run "explorer" with administrative priviledges, I can navigate to "c:\ProgramData" but not see anything past that... Through some looking, I found out that "c:\ProgramData\Start Menu" is a protected operating system file. So I turned on the setting to see it. So now I can see it, but not go into it.
Using system internals, I elevated an explorer.exe to "system" access and still can't go into the folder (System internal elevation reference: http://verbalprocessor.com/2007/12/05/running-a-cmd-prompt-as-local-system/)
I right clicked on the folder and checked out the security tab. It looks like even my "System" user has limited access. I find this a bit baffling, that I can run the command from an admin command prompt that will write the shortcut to the desktop, but going through this other process I cannot... I also find the access to be a bit inconsistent.

Mark MSI so it has to be run as elevated Administrator account

I have a CustomAction as part of an MSI.
It MUST run as a domain account that is also a member of the local Administrators account.
It can't use the NoImpersonate flag to run the custom action as NT Authority\System as it will not then get access to network resources.
On Vista/2008 with UAC enabled if NoImpersonate is off then it will run as the executing user but with the unprivileged token and not get access to local resources such as .installState. See UAC Architecture
Anyone know of a way to either
Force the MSI to run with the elevated token in the same way that running from an elevated command prompt does?
Force the CustomAction to run elevated (requireAdministrator in manifest doesn't appear to work)?
Work out if UAC is enabled and if it hasn't been ran elevated and if so warn or cancel the installation?
Answering my own question for any other poor s0d looking at this.
You can't add a manifest to an MSI. You could add a SETUP.EXE or bootstrapper to shell the MSI and manifest that with requireAdministrator but that defeats some of the point of using an MSI.
Adding a manifest to a CustomAction does not work as it is ran from msiexec.exe
The way I have tackled this is to set the MSIUSEREALADMINDETECTION property to 1 so the Privileged condition actually works and add a Launch Condition for Privileged that gives an error message about running via an elevated command prompt and then quits the installation.
This has the happy side effect - when an msi is ran from an elevated command prompt deferred CustomActions are ran as the current user with a full Administrator token (rather than standard user token) regardless of the NoImpersonate setting.
More details - http://www.microsoft.com/downloads/details.aspx?FamilyID=2cd92e43-6cda-478a-9e3b-4f831e899433
[Edit] - I've put script here that lets you add the MSIUSEREALADMINDETECTION property as VS doesn't have ability to do it and Orca's a pain.
requireAdministrator in the manifest should work.
You can also use a bootloader .exe file which can use ShellExecute with "RUNAS" as the verb (you can use 7-zip to create the bootloader, or there are many other ways).
You can creating a simple sfx archive file for msi file with Winrar and these options:
Setup tab > Run after execution input: your msi file name
Advanced tab > Mark Request Administrative access option checkbox

Uninstall Command Fails Only in Release Mode

I'm able to successfully uninstall a third-party application via the command line and via a custom Inno Setup installer.
Command line Execution:
MSIEXEC.exe /x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn
Inno Setup Command:
[Run]
Filename: msiexec.exe; Flags: runhidden waituntilterminated;
Parameters: "/x {{14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
StatusMsg: "Uninstalling Service...";
I am also able to uninstall the application programmatically when executing the following C# code in debug mode.
C# Code:
string fileName = "MSIEXEC.exe";
string arguments = "/x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
Process process = Process.Start(psi);
string errorMsg = process.StandardOutput.ReadToEnd();
process.WaitForExit();
The same C# code, however, produces the following failure output when run as a compiled, deployed Windows Service:
"This action is only valid for products that are currently installed."
Additional Comments:
The Windows Service which is issuing
the uninstall command is running on
the same machine as the code being
tested in Debug Mode. The Windows
Service is running/logged on as the
Local system account.
I have consulted my application logs
and I have validated that the
executed command arguments are thhe
same in both debug and release mode.
I have consulted the Event Viewer
but it doesn't offer any clues.
Thoughts? Any help would be greatly appreciated. Thanks.
Step 1: Check the MSI error log files
I'm suspicious that your problem is due to running as LocalSystem.
The Local System account is not the same as a normal user account which happens to have admin rights. It has no access to the network, and its interaction with the registry and file system is quite different.
From memory any requests to read/write to your 'home directory' or HKCU under the registry actually go into either the default user profile, or in the case of temp dirs, c:\windows\temp
I've come across similar problems in the past with installation, a customer was using the SYSTEM account to install and this was causing all sorts of permission problems for non-administrative users.
MSI log files aren't really going to help if the application doesn't appear "installed", I'd suggest starting with capturing the output of MSIINV.EXE under the system account, that will get you an "Inventory" of the currently installed programs (or what that user sees installed) http://blogs.msdn.com/brada/archive/2005/06/24/432209.aspx
I think you probably need to go back to the drawing board and see if you really need the windows service to do the uninstall. You'll probably come across all sorts of Vista UAC issues if you haven't already...
Thanks to those offering help. This appears to be a permissions issue. I have updated my service to run under an Administrator account and it was able to successfully uninstall the third-party application. To Orion's point, though the Local System account is a powerful account that has full access to the system -- http://technet.microsoft.com/en-us/library/cc782435.aspx -- it doesn't seem to have the necessary rights to perform the uninstall.
[See additional comments for full story regarding the LocalSystem being able to uninstall application for which it installed.]
This is bizarre. LocalSystem definitely has the privileges to install applications (that's how Windows Update and software deployment in Active Directory work), so it should be able to uninstall as well.
Perhaps the application is initially installed per-user instead of per-machine?
#Paul Lalonde
The app's installer is wrapped within a custom InnoSetup Installer. The InnoSetup installer, in turn, is manually executed by the logged in user. That said, the uninstall is trigged by a service running under the Local System account.
Apparently, you were on to something. I put together a quick test which had the service running under the LocalSystem account install as well as uninstall the application and everything worked flawlessly. You were correct. The LocalSystem account has required uninstall permissions for applications in which it installs. You saved the day. Thanks for the feedback!

Categories

Resources