Повышение привилегий не работает с 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, когда у вас есть доступ к исходному коду дочернего процесса.