Reputation: 149
I have a small command that allows me to query information from CMD, however it needs admin privileges (not at my application level but at the CMD level) Only reason I am going this route is because I couldn't get WMI to query bitlocker settings for the life of me and this project needs to get off of my desk.
if (bitA.Text == "Bitlocker Available")
{
Process cmd2 = new Process();
cmd2.StartInfo.Verb = "runas";
cmd2.StartInfo.FileName = "cmd.exe";
cmd2.StartInfo.Arguments = "/c ping 8.8.8.8";
cmd2.StartInfo.UseShellExecute = false;
cmd2.StartInfo.RedirectStandardOutput = true;
cmd2.StartInfo.RedirectStandardError = true;
cmd2.Start();
//* Read the output (or the error)
string output2 = cmd2.StandardOutput.ReadToEnd();
bitB.Text = output2;
cmd2.WaitForExit();
}
Upvotes: 2
Views: 3809
Reputation: 40818
As I said in my comment, the issue is that the "runas" verb requires UseShellExecute to be true, but redirection requires UseShellExecute to be false. This makes the problem sort of tricky, but the key is start a process as admin that you can communicate with via some kind of IPC, then this process starts whatever process you want to redirect output from. It can even be the same executable just switching on the arguments received. If I was writing a library, I would probably embed a shim executable as an assembly resource. Here is a simple example using named pipes:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.IO.Pipes;
using System.IO;
namespace AdminRedirect
{
class Program
{
private static readonly int ProcessId = Process.GetCurrentProcess().Id;
static void Main(string[] args)
{
bool isAdmin = IsAdministrator();
Console.WriteLine("Id = {0}, IsAdmin = {1}", ProcessId, isAdmin);
if (!isAdmin)
{
Console.WriteLine("Press any key to spawn the admin process");
Console.ReadKey(intercept: true);
string pipeName = "mypipe-" + Guid.NewGuid();
Process cmd = new Process()
{
StartInfo =
{
Verb = "runas",
Arguments = pipeName,
FileName = typeof(Program).Assembly.Location,
UseShellExecute = true
}
};
using (var pipeStream = new NamedPipeServerStream(pipeName))
{
cmd.Start();
Console.WriteLine("Started {0}", cmd.Id);
pipeStream.WaitForConnection();
Console.WriteLine("Received connection from {0}", cmd.Id);
using (var reader = new StreamReader(pipeStream))
{
string line;
while((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
Console.WriteLine("Hit any key to end");
Console.ReadKey(intercept: true);
}
else
{
if (args.Length > 0)
{
string pipeName = args[0];
Console.WriteLine("Opening client pipe: {0}", pipeName);
using (var pipeStream = new NamedPipeClientStream(pipeName))
{
pipeStream.Connect();
using (var writer = new StreamWriter(pipeStream))
{
StartChildProcess(writer);
}
}
}
else
{
Console.WriteLine("We are admin and not piping, so just run");
StartChildProcess(Console.Out);
Console.WriteLine("Hit any key to end");
Console.ReadKey(intercept: true);
}
}
}
private static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
private static void StartChildProcess(TextWriter output)
{
var cmd = new Process()
{
StartInfo =
{
FileName = "cmd.exe",
Arguments = "/c ping 8.8.8.8",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
cmd.Start();
string procOutput = cmd.StandardOutput.ReadToEnd();
output.Write("Id: {0}, Output:{1}", cmd.Id, procOutput);
}
}
}
Upvotes: 1
Reputation: 127543
To use runas
you must have UseShellExecute
be true, however to use any of the redirect methods you must have UseShellExecute
be false. You can not have both at the same time.
If you need to redirect the output and elevate at the same time you must do the following steps:
runas
and UseShellExecute = true
to generate a elevated process. ping.exe
with UseShellExecute = false
and redirects the outputs. 1: it could be your same EXE but passing some special command line arguments to put it in this new mode
Upvotes: 0
Reputation: 1174
You can indicate the new process should be started with elevated permissions by setting the Verb property of your startInfo object to 'runas', as follows:
startInfo.Verb = "runas";
This will cause Windows to behave as if the process has been started from Explorer with the "Run as Administrator" menu command. The user will be prompted with the UAC to confirm they want to do it.
Edit: I see you have that verb set already. Are you asking if you can circumvent the UAC? That would be kind of silly, otherwise virus-writers and so forth could get around the security check with one line of code.
Upvotes: 2