1
votes

Background

My application (.NET, C#) performs an in-app upgrade. Depending on installation configuration, the upgrade may need to launch a separate process that requires Administrator privileges. The launched program's manifest specifies that it requires Administrator privileges.

This normally works fine, but if UAC is disabled, and the user is not an admin, then it fails miserably. See below.

Scenarios

  • UAC is enabled, and the user is an admin - Windows prompts for elevation, and the program executes successfully.
  • UAC is enabled, and the user is not an admin - Windows prompts for credentials, and the program executes successfully.
  • UAC is disabled, and the user is an admin - No prompts, the program executes successfully.
  • UAC is disabled, and the user is not an admin - No prompts, the program starts but fails miserably.

This fourth scenario is the one that I want to solve. I have a rather large customer company that has a policy of turning off UAC on all corporate PCs, for whatever reason.

Mitigation

The simplest solution is to detect this fourth scenario and give the user guidance. I have no problem detecting when this fourth scenario is in effect, and I can then open up an Explorer window to a directory containing the program to execute, and a text file that walks the user through the process of Shift-Right-Click -> "Run as different user".

Desired solution

If I detect that I am in this fourth scenario, then I perform some coding magic to automatically start the process from my application AS IF the user had manually opted to "Run as different user".

I don't know how to implement this solution. I tried to set ProcessStartInfo.Verb = "runas", as I have seen suggested, but that doesn't seem to do anything useful in the absence of UAC. Any ideas?

1
Imo the correct verb would be "runasuser" not "runas". it has some pitfalls though like the process not returning a proper object to the main program but if you have a launcher that does not care for this information and just starts the seperate updater.exe it should work fineSyberdoor
This is the kind of Big Enterprise scenario where you simply cannot run programs that require elevation. You can ask pretty-please to get the UAC prompt enabled again but that still doesn't help, the user doesn't know the password. You'll have to talk to a bigwig at the enterprise, you have a "no", maybe you'll get a "yes".Hans Passant
@Syberdoor - Thank you very much! That works. Feel free to submit an answer, and I will mark it as accepted. As you said, I don't get an object back, so I can't detect when the process completes. I may play around with utilizing Process.GetProcessByName() to detect when the process exits, and then use artifacts to determine success or failure. Sound reasonable?danBhentschel
I'm not expert enough nor do I know enough to say what's the best method if you need communication between the spawned process and the parent but it should at least be possible. If your name is unique enough and runtime is long checking will probably work, or you could even use wcf namedpipes or something for inter process communicationSyberdoor
Just an extra note, in case anyone goes down this path in the future... Regardless of which method used to communicate between the parent and child processes, you might need to use something like Elevating user credentials using runasuser verb in your solution. Keep in mind that the user can press Cancel on the credentials prompt, in which case the child process will never be started at all.danBhentschel

1 Answers

2
votes

The correct verb for this case would be

ProcessStartInfo.Verb = "runasuser"

It works well to trigger the "run as different user" authentication dialog for another process. One possible downside I found was that you will not get a proper process object returned, so you get no handle for that new process. Also it is not really possible to restart your own application with this method as the authentication dialog is running as a thread of the spawning application and only after authentication is a new process created. So if you want to "restart" your application a launcher or some other trick would probably be needed.