【问题标题】:Elevating privileges doesn't work with UseShellExecute=false提升权限不适用于 UseShellExecute=false
【发布时间】:2011-04-05 12:08:49
【问题描述】:

我想启动一个具有提升权限但隐藏窗口的子进程(实际上是相同的控制台应用程序)。

接下来我做:

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。为什么??

【问题讨论】:

  • 顺便说一句,你可以写DataReceivedEventHandler actionWrite = ...process.ErrorDataReceived += actionWrite
  • 您能否使用 UseShellExecute = true、Verb = "runas" 和 ErrorDataReceived 事件作为@SLaks 评论进行测试?

标签: c# uac processstartinfo elevated-privileges


【解决方案1】:

ProcessStartInfo.Verb 只有在进程由 ShellExecuteEx() 启动时才会生效。这需要 UseShellExecute = true。重定向 I/O 和隐藏窗口只有在进程由 CreateProcess() 启动时才能起作用。这需要 UseShellExecute = false。

嗯,这就是它不起作用的原因。不确定禁止启动绕过 UAC 的隐藏进程是否是故意的。大概。 非常可能。

检查 this Q+A 以获得显示 UAC 提升提示所需的清单。

【讨论】:

  • 非常感谢 WinAPI 的幕后描述。您认为如何根据需要为具有隐藏窗口的进程获得提升的权限?或者这是相互排斥的东西?
  • 是否可以使用清单打开/关闭? IE。当我第一次(手动)启动我的应用程序时 - 不要使用清单,当第二次(以编程方式)时 - 强制使用。
  • 不可能在用户不知情的情况下以提升的权限启动进程。您需要一个单独的 .exe,以便它有自己的清单。基本上你只需要 Main() 方法。
  • 我不想向用户隐藏进程启动,我仍然需要他的 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】:

检查this answer

这似乎提供了一种解决方法。但是我建议您在可以访问子进程的源代码时尝试其他方法,例如Named Pipes

【讨论】:

  • 我还没有测试过 UAC 文章方法,尽管它本身包含一个示例。但是,如果您指的是命名管道的示例,您只需稍加搜索即可轻松找到其中的许多(如thisthis)。关键是,就像 I/O 重定向一样,您也可以使用带有命名管道的文本流来发送和接收数据(即使两个进程位于不同的机器上)。当然,您必须处理一些细微差别才能获得完整的应用程序。
  • @abatishchev 恕我直言,最好使用跟踪到文件,而不是重定向输出,动词 = runas。命名管道要复杂得多,调试起来也很容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 1970-01-01
相关资源
最近更新 更多