Повышающие привилегии не работают с UseShellExecute = false

Я хочу запустить дочерний процесс (действительно то же самое, консольное приложение) с повышенными привилегиями, но со скрытым окном.

Далее:

var info = new ProcessStartInfo(Assembly.GetEntryAssembly().Location)
{
    UseShellExecute = true, // !
    Verb = "runas", 
};

var process = new Process
{
    StartInfo = info
};

process.Start();

и это работает:

var identity = new WindowsPrincipal(WindowsIdentity.GetCurrent());
identity.IsInRole(WindowsBuiltInRole.Administrator); // returns true

Но UseShellExecute = true создает новое окно, и я также не могу перенаправить вывод.

Итак, когда я сделаю следующее:

var info = new ProcessStartInfo(Assembly.GetEntryAssembly().Location)
{
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    UseShellExecute = false, // !
    Verb = "runas"
};

var process = new Process
{
    EnableRaisingEvents = true,
    StartInfo = info
};

DataReceivedEventHandler actionWrite = (sender, e) =>
{
    Console.WriteLine(e.Data);
};

process.ErrorDataReceived += actionWrite;
process.OutputDataReceived += actionWrite;

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

Это не повышает привилегии и код выше возвращает false. Почему??

Ответ 1

ProcessStartInfo.Verb будет иметь эффект только в том случае, если процесс запускается с помощью ShellExecuteEx(). Для чего требуется UseShellExecute = true. Перенаправление ввода-вывода и скрытие окна могут работать, только если процесс запускается CreateProcess(). Для этого требуется UseShellExecute = false.

Ну, почему это не работает. Не уверен, что запрет запуска скрытого процесса, который обходит UAC, был намеренным. Вероятно. Очень вероятно.

Отметьте этот Q + A для манифеста, который вам нужно отобразить приглашение повышения UAC.

Ответ 2

В моем случае было нормально получать выходные данные после того, как завершился дочерний процесс. Вот решение, которое я придумал. Он использует временный файл:

var output = Path.GetTempFileName();
var process = Process.Start(new ProcessStartInfo
{
    FileName = "cmd",
    Arguments = "/c echo I'm an admin > " + output, // redirect to temp file
    Verb = "runas", // UAC prompt
    UseShellExecute = true,
});
process.WaitForExit();
string res = File.ReadAllText(output);
// do something with the output
File.Delete(output);

Ответ 3

Отметьте этот ответ.

Это, как представляется, обеспечивает обходное решение. Но я рекомендую попробовать другие методы, такие как Named Pipes, когда у вас есть доступ к исходному коду дочернего процесса.