5
votes

I'm working on a WPF application targeting .NET 3.0. I need to call an exe which requires administrative privileges. I can get the UAC to prompt for permission by using something like:

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Verb = "runas";
startInfo.UseShellExecute = true;
startInfo.FileName = "target.exe";

Process p = new Process();
p.StartInfo = startInfo;
p.Start();

My problem is I need to redirect standard output, and doing so with UseShellExecute = true results in an exception stating that:

The Process object must have the UseShellExecute property set to false in order to redirect IO streams

However, setting it to false results in the UAC not prompting for permission and I get an exception stating:

The requested operation requires elevation

How can I redirect standard output and prompt for UAC?

I have seen this similar question, however the solution is to use the app.manifest to give my application administrative privileges. This is something I cannot do due to requirements.

2
Based on the behavior I've seen in many applications regarding special run properties (as a shell for instance) I assume that the UAC does not prompt in those cases by design. From your description, this is the kind of program I would be right clicking and running as administrator.Logarr
You could write a utility ElevateRedir.exe to help you here. For example, "ElevateRedir.exe /port 54321 /path Target.exe". ElevateRedir would send output from Target.exe back to your application with a socket that it received through STDOUT redirect. You'd launch ElevateRedir as Administrator, and it could launch Target.exe (no need for runas now because the parent process was admin, I believe). Redirect it's standard out, and forward it on to your app through a predefined socket port. Your initial application would just need to listen to the TCP port to get the outputAlan
Can you test Name Pipes ? Or maybe you can test UseShellExecute =, true and Verb = runas, and process.ErrorDataReceived += actionWriteEvent ? Or can you test @Alan workaroundKiquenet

2 Answers

3
votes

UseShellExecute must be set to false to redirect IO, and to true to use the Verb property. So you can't.

But this article seems do the magic, although I haven't tested it.

It's written in C++, but a wrapper API can easily be created to be called from C# by using DllImport.


Note: If you want to pass data between the two programs and have access to the target program's source code, you can easily re-design you application to use Named Pipes instead of redirecting standard I/O.

2
votes

There is another pretty simple solution:

If you want to run a child-executable elevated AND redirect the output (optionally including window hiding), then your main code must be running elevated too. This is a security requirement.

To accomplish this:

  1. Manually edit your app.manifest in your project folder.
  2. Find the comment regarding UAC Manifest Options, you will see the 3 examples of requestedExecutionLevel.
  3. Under the comment, locate the tricky asInvoker which is currently enabled, and replace it with requireAdministrator.
  4. Restart Visual Studio in order to take into effect, and after re-building your app it should have the typical UAC shield icon.

Now your code will run elevated, everything that it launches will be elevated too, and you can also capture output streams. Here is an example in VB.NET:

Dim startInfo As New ProcessStartInfo
startInfo.Verb = "runas"
startInfo.FileName = "subprocess-elevated.exe"
startInfo.Arguments = "arg1 arg2 arg3"
startInfo.WorkingDirectory = Environment.CurrentDirectory
startInfo.WindowStyle = ProcessWindowStyle.Hidden
startInfo.CreateNoWindow = True
Dim p As Process = New Process()
p.StartInfo = startInfo
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.RedirectStandardError = True
p.Start()
Console.WriteLine(p.StandardOutput.ReadToEnd)
Console.WriteLine(p.StandardError.ReadToEnd)
p.WaitForExit()