Повышение привилегий не работает с 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. Зачем??

3 ответа

Решение

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

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

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

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

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);

Проверьте этот ответ.

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

Другие вопросы по тегам