以编程方式提升进程权限?

174

我正试图使用通过Process.Start调用的InstallUtil.exe安装一个服务。这是代码:

ProcessStartInfo startInfo = new ProcessStartInfo (m_strInstallUtil, strExePath);
System.Diagnostics.Process.Start (startInfo);

m_strInstallUtil是指“InstallUtil.exe”完全限定路径和可执行文件名,strExePath是指我的服务的完全限定路径/名称。

从提升的命令提示符中运行命令行语法可以正常工作;使用上述代码从我的应用程序中运行不起作用。我认为我正在处理一些进程提升问题,那么如何以提升状态运行我的进程?我需要查看 ShellExecute 吗?

这全部在Windows Vista上进行。我正在以管理员特权运行VS2008调试器中的进程。

我还尝试设置 startInfo.Verb = "runas";,但似乎并未解决问题。


1
在我加入了startInfo.UseShellExecute = true;以及startInfo.Verb = "runas";之后,它对我来说运行得很好。 - Matt
7个回答

198

您可以通过将startInfo对象的Verb属性设置为“runas”来指示新进程应该以提升的权限启动,如下所示:

startInfo.Verb = "runas";

这将使Windows表现得像通过“以管理员身份运行”菜单命令从资源管理器启动进程一样。

这确实意味着用户需要确认UAC提示:如果这是不希望的(例如因为它会在一个漫长的过程中发生),您需要通过创建和嵌入应用程序清单(UAC)以要求 'highestAvailable' 执行级别来使用高权限运行整个主机进程:这将导致UAC提示出现在您的应用程序启动时,并导致所有子进程在不需要额外提示的情况下以高权限运行。

编辑:我看到你刚刚编辑了你的问题,说明“runas”对你没有起作用。这真的很奇怪,因为它应该可以(并且在我的几个生产应用程序中也可以)。然而,通过嵌入清单要求父进程以高权限运行肯定是可行的。


11
“runas” 对我也没用。可能只有在关闭用户帐户控制(UAC)时才能使用? - Dirk Vollmar
20
@LukePuplett 我会感谢他们。这是一种很好的方式,可以在不完全隔离用户角色的情况下减轻根套件安装的影响。 - Colton
6
@Sparksis,不过还有另一种观点。那些知道如何保护自己操作系统的人,他们不需要使用UAC就能做到。而那些不懂防御的新手用户,在看到UAC窗口时总是会点击“是”。此外,没有什么可以阻止坏黑客病毒编写者使用漏洞来绕过它;) 所以我同意LukePuplett的观点=) - Jet
35
看起来你需要设置 startInfo.ShellExecute=true 才能使这个工作...此外我无法让这个方法在网络共享的可执行文件上运行(必须将它们复制到本地临时目录才能运行)... - TCC
11
@Jet,抱歉但这是错误的想法。每次在安装过程中显示 UAC 对话框,都表示系统出现了问题。UAC 能够发挥价值的时候是当你看到一个不需要管理员权限却弹出 UAC 窗口的时候。无论我们中的任何一位有多么专业,你都不能神奇地阻止零日漏洞或者恶意下载(例如最近在官方诺贝尔奖网站上发生的事件)。如果你浏览到该网站并收到 UAC 提示,则会知道存在问题。关闭 UAC 后,您将永远不会知道自己已经加入了僵尸网络。这种提前警告的代价就是偶尔需要点击“是”。 - Basic
显示剩余6条评论

58

以下代码将上述所有内容整合在一起,并以管理员权限重新启动当前的WPF应用程序:

if (IsAdministrator() == false)
{
    // Restart program and run as admin
    var exeName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
    ProcessStartInfo startInfo = new ProcessStartInfo(exeName);
    startInfo.Verb = "runas";
    System.Diagnostics.Process.Start(startInfo);
    Application.Current.Shutdown();
    return;
}

private static bool IsAdministrator()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(identity);
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}


// To run as admin, alter exe manifest file after building.
// Or create shortcut with "as admin" checked.
// Or ShellExecute(C# Process.Start) can elevate - use verb "runas".
// Or an elevate vbs script can launch programs as admin.
// (does not work: "runas /user:admin" from cmd-line prompts for admin pass)

更新:推荐使用应用程序清单的方法:

在 Visual Studio 中右键点击项目,选择添加,新建应用程序清单文件,并将文件更改为如上所示的 requireAdministrator。

原始方法存在一个问题:如果您将重启代码放在 app.xaml.cs 的 OnStartup 中,即使调用了 Shutdown,它仍然可能会短暂地启动主窗口。如果没有运行 app.xaml.cs 初始化并且在某些竞争条件下,我的主窗口会崩溃。


请参见以下改进。 - JCCyC
requireAdministrator 在我的情况下没有起作用。所以我不得不按照你的方式去做。这解决了我的问题!谢谢。但是我必须将 Single Instance Application 设置为 false。 - chris
这对我有用。我还将原始的 string[] args 传递给了重新启动的进程。 - DotNetPadawan
1
好的例子。在.NET 5 WinForms中,您必须包含以下行:startInfo.UseShellExecute = true; - A. Niese
你可能想把Process.Start放在try..catch中,以防用户点击UAC对话框中的“否”。否则,您可能会遇到挂起的情况:https://dev59.com/32Ag5IYBdhLWcg3wpMSz - A. Niese
检查管理员的代码正是我所需要的。+1 - cr1pto

24

8
[PrincipalPermission(SecurityAction.Demand, Role = @"BUILTIN\Administrators")]

如果运行用户是管理员组的成员,那么无需启动新进程即可完成此操作,而且不需要 UAC。


5
使用这段代码时,我遇到了一个许可错误:“请求安全实体许可失败。” :( - Leonardo
1
也许是“如果运行用户是管理员成员”* - hB0
1
有趣的是,这可以应用于任何方法,不仅仅是操作方法(我甚至尝试在 ASPX 页面中定义的方法上使用它)。 - Simon_Weaver
1
根据微软的文档,截至2023年,它指出:“代码访问安全性(CAS)已在所有版本的.NET Framework和.NET中被弃用。最近的.NET版本不支持CAS注释,并且如果使用与CAS相关的API,则会产生错误。开发人员应寻找替代手段来完成安全任务。” - nwsmith
@nwsmith感谢您的更新 - 这是一种桌面式的情况,新的规格可能存在于MAUI内部?您能列出在.NET6/7中实现它的新方法吗? - hB0
1
@hB0 获取可执行文件需要管理员权限的方法是在“ .exe”上应用“ .manifest”作为后期构建步骤。我选择使用微软的“ mt.exe”实用程序来完成此操作,按照此处的说明进行操作。 但是,如果您使用的是Visual Studio,则可以自动化此步骤。 - nwsmith

6

我知道这是一个非常老的帖子,但我想分享一下我的解决方案:

System.Diagnostics.ProcessStartInfo StartInfo = new System.Diagnostics.ProcessStartInfo
{
    UseShellExecute = true, //<- for elevation
    Verb = "runas",  //<- for elevation
    WorkingDirectory = Environment.CurrentDirectory,
    FileName = "EDHM_UI_Patcher.exe",
    Arguments = @"\D -FF"
};
System.Diagnostics.Process p = System.Diagnostics.Process.Start(StartInfo);

注意: 如果VisualStudio已经以管理员权限运行,则UAC对话框将不会显示。要测试它,请从bin文件夹运行exe文件。


1
工作的代码。谢谢。 - undefined

3

你应该使用模拟来提升状态。

WindowsIdentity identity = new WindowsIdentity(accessToken);
WindowsImpersonationContext context = identity.Impersonate();

完成后不要忘记撤销模拟上下文。


33
你没有说明如何获取accessToken。当UAC(用户账户控制)启用时,LogonUser将提供用户受限的安全上下文。 - cwa
如果您正在使用VSTS,可以在Web Portal的“设置”中获取个人访问令牌。(在用户图片旁边寻找设置图标。)[MSDocs] (https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page) - Su Llewellyn

0

在Windows中,有一种启动需要提权的进程而不必在父进程中具备提权权限的替代方式,即使用 任务计划程序。您可以手动创建一个任务,并在常规选项卡中勾选以最高权限运行。然后,您可以使用任务计划程序库以编程方式执行此任务。

注意:动态创建此类任务是不可能实现的,因为这将要求您的进程拥有提权权限。

使用 TaskScheduler 库查找并运行任务如下所示:

TaskService.Instance.RootFolder.AllTasks
        .FirstOrDefault(x => x.Name == "My elevated Task").Run();

或者,您可以通过编程方式创建任务(需要提升权限一次),而无需手动创建任务,稍后再启动它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接