Starting another process with elevation using different user credentials

From MSDN:

You cannot elevate an already running process. Thus, you should refactor your app to be separated into admin & non-admin operations - running the default application with normal privileges and starting another elevated process for each administrative operation.

Let's work with that, assuming you request administrator rights from the outset on the processes that require them. Based upon the context you've provided:

The issue seems to be setting UseShellExecute to false (as both approaches work fine when this is not the case), but I have to set it to false in order to launch the process under a different user account.

As you mentioned, exactly as noted in the documentation for UseShellExecute:

UseShellExecute must be false if the UserName property is not Nothing or an empty string, or an InvalidOperationException will be thrown when the Process.Start(ProcessStartInfo) method is called.

We now know you're executing your program directly instead of through the use of a shell. This is valuable information.

Backpathing through the documentation, the docs for ProcessStartInfo carry the following security note:

This class contains a link demand at the class level that applies to all members. A SecurityException is thrown when the immediate caller does not have full-trust permission. For details about security demands, see Link Demands.

So, you don't have the right Link Demand. While trying to solve your permissions issue, you inadvertently created another permissions issue.

The upshot is you need to decorate your calling method with the right Security Demand, which should be FullTrust. You can do this declaratively or imperatively within your code.

(Additional reading)

If you're authoring a Windows Installer (MSI) application, and updating it using MSPs, then Windows Installer has built-in support for exactly your scenario: - check out User Account Control (UAC) Patching.

It works basically like this:

  • When you author the original MSI, You generate a certificate, and you put its public key (or something like that) in the MSI.
  • The target machine's admin installs the MSI on the machine.
  • You author an update (MSP), and sign it with the certificate.
  • Any user on the target machine can now install the update - Windows Installer will validate the certificate against the public key in the original MSI, and agree to install if so. I don't think you'll get a UAC prompt at all, though I'm not sure.

i was surprised there's no way to do this, until i found an on blog entry by Chris Jackson:

Why Can’t I Elevate My Application to Run As Administrator While Using CreateProcessWithLogonW?

You need a bootstrapper. Some process which will let you do the transition to the alternate user, which could be responsible for running the requireAdministrator application. So, you could design something like this:

enter image description here

Why don’t we just create the ShellExecuteWithLogonW API? I’ll never say never, and we might at some point. But today, the use cases for this APIs have been use cases where there has been an alternate design which is superior.

The most common request is for people writing home-grown software deployment software, where they’d like to encode credentials right into the app and elevate their own process. The real problem here is not the lack of the API, it’s that you have admin credentials encoded in your app for the world to read.

So the solution requires ShellExecute, it's the only one that knows how to trigger a Consent dialog.

It brings up a good point: What are you doing with a person's password already?

Bonus Chatter

There's no UAC on Server Core because there's no windows to show a consent prompt.