如何仅在需要时提升特权?


85

此问题适用于Windows Vista!

我有一个通常无需管理员权限即可运行的应用程序。有一项活动确实需要管理特权,但是当我知道大部分时间用户甚至都不会使用该功能时,我不想以更高的特权启动应用程序本身。

我正在考虑某种方法,通过该方法我可以提高某些事件(例如,按下按钮)的应用程序的特权。例:

如果用户单击此按钮,则系统会提示他UAC对话框或同意。我怎样才能做到这一点?

Answers:


58

我认为无法提升当前正在运行的流程。据我了解,Windows Vista内置了该功能,该功能可在启动时为进程赋予管理员特权。如果查看使用UAC的各种程序,则应该看到它们每次需要执行管理操作时实际上都会启动一个单独的进程(任务管理器是一个,Paint.NET是另一个,而后者实际上是一个.NET应用程序。 )。

解决此问题的典型方法是在启动提升的进程时指定命令行参数(abatishchev的建议是执行此操作的一种方法),以便启动的进程只知道显示某个对话框,然后在执行此操作后退出完成。因此,用户应该几乎不会注意到已经启动了一个新进程,然后退出了该进程,而是看起来好像是在同一应用程序中打开了一个新对话框(尤其是如果您使用一些黑客工具来创建该新进程的主窗口)提升的流程是父流程的子流程)。如果您不需要UI来提升访问权限,那就更好了。

有关在Vista上进行UAC的完整讨论,我建议您通过关于该主题的文章非常仔细地看到(代码示例在C ++中,但是我怀疑您需要使用WinAPI和P / Invoke来完成C#中的大多数操作无论如何)。希望您现在至少看到正确的方法,尽管设计符合UAC的程序绝非易事...


4
Windows 7是否有任何变化?答案是否定的,“不,请使用新进程”?谢谢...
Radim Vansa

2
抱歉,Windows 7没有任何变化。(据我所知,我是Win7的普通用户/开发人员。)
Noldorin

2
这正是任务管理器的工作方式。当您单击按钮以显示所有用户的任务时,该任务存在,当前任务管理器将调用具有管理员权限的另一个任务管理器。
Natalie Adams

3
@NathanAdams从技术上讲,它首先打开新的任务管理器。否则,开幕式在做什么?:-)
wizzwizz4 '04

16

正如有人说

Process.StartInfo.UseShellExecute = true;
Process.StartInfo.Verb = "runas";

将以admin身份运行该过程,以执行注册表所需的任何操作,但将以普通权限返回到您的应用。


这涉及跨越一个新的过程。对?我一直在寻找提升当前流程本身的特权。
Hemant

尝试使用Process.GetCurrentProcess()
abatishchev

27
您无法提升当前正在运行的进程。
雅各布·普罗菲菲特

1
这不是真的。您可以更改进程的所有者,并设置DACL和ACL值的用户给予他们行政权力....
Nightforce2

4
@ nightforce2:如果您已经拥有管理权限(即您已经被提升),那么肯定只有这样。否则AdjustTokenPrivileges等将完全失败,不是吗?
本·施威恩

13

以下MSDN KB文章981778描述了如何“自我提升”应用程序:

http://support.microsoft.com/kb/981778

它包含Visual C ++,Visual C#,Visual Basic.NET中的可下载示例。

这种方法可以避免启动单独进程的需要,但实际上是重新启动了原始应用程序,以提升的用户身份运行。但是,在某些情况下,在单独的可执行文件中复制代码并不现实,这可能仍然非常有用。

要删除高程,您需要退出应用程序。


1
一个按钮很方便,但是当您想要一个菜单​​项使用相同的按钮时,您将陷入一团混乱的困境。
Nyerguds


答案的链接已失效,评论的链接指向2608项长列表。
DonBoitnott

您可以在这里
mirh


2

这个简单的例子也许有人派上用场:

using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System.Security.Principal;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    internal static class Program
    {
        private class Form1 : Form
        {
            internal Form1()
            {
                var button = new Button{ Dock = DockStyle.Fill };
                button.Click += (sender, args) => RunAsAdmin();
                Controls.Add(button);

                ElevatedAction();
            }
        }

        [STAThread]
        internal static void Main(string[] arguments)
        {
            if (arguments?.Contains("/run_elevated_action") == true)
            {
                ElevatedAction();
                return;
            }

            Application.Run(new Form1());
        }

        private static void RunAsAdmin()
        {
            var path = Assembly.GetExecutingAssembly().Location;
            using (var process = Process.Start(new ProcessStartInfo(path, "/run_elevated_action")
            {
                Verb = "runas"
            }))
            {
                process?.WaitForExit();
            }
        }

        private static void ElevatedAction()
        {
            MessageBox.Show($@"IsElevated: {IsElevated()}");
        }

        private static bool IsElevated()
        {
            using (var identity = WindowsIdentity.GetCurrent())
            {
                var principal = new WindowsPrincipal(identity);

                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
        }

    }
}

1

我知道这是一篇旧文章,但这是对任何遇到MarcP建议的人的回应。他引用的msdn确实确实在所有代码示例中重新启动了应用程序。代码示例使用runas其他建议中已经提出的动词。

我下载了代码以确保确定,但这是来自原始msdn文章:

4.单击是,批准高程。然后,原始应用程序重新启动,以提升的管理员身份运行。
5.关闭应用程序。


1
您可以添加有问题的MSDN链接吗?我找不到名为MarcP的用户。
阿尔夫,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.