如何在C#中以管理员模式启动进程

115

我有一个Visual Studio Windows应用程序项目。我已经添加了下载安装程序更新文件的代码。下载完成后,安装程序需要管理员权限才能运行。我已经添加了一个清单文件。

当用户点击DownloadUpdate.exe时,UAC会提示用户获取管理员权限。因此,我假设在DownloadUpdate.exe中创建和调用的所有进程都将以管理员身份运行。因此,我使用以下代码调用我的已下载文件:

Process p = new Process();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.FileName = strFile;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;

1
不,你不能假设所有从DownloadUpdater.exe启动的进程都在管理员模式下运行。事实上,那将是一次可怕的安全漏洞。如果你运行另一个需要管理员权限的进程,用户将再次被提示。 - Waldo Bronchart
9个回答

91

尝试这个:

//Vista or higher check
if (System.Environment.OSVersion.Version.Major >= 6)
{
   p.StartInfo.Verb = "runas";
}

或者,使用应用程序清单的方式


9
请注意,如果没有 p.StartInfo.UseShellExecute = true;,这个答案可能不起作用。 - anion
1
@anion 我不得不包含 UseShellExecute = true 才能使 .Net 6 程序成功以管理员身份启动另一个程序。在 .Net Framework 4.7.1 中,我不需要包含它。 - OSA413

58

首先,你需要在你的项目中包含以下内容:

using System.Diagnostics;

接下来,您可以编写一个通用方法,用于使用不同的.exe文件。代码如下:

public void ExecuteAsAdmin(string fileName)
{
    Process proc = new Process();
    proc.StartInfo.FileName = fileName;
    proc.StartInfo.UseShellExecute = true;
    proc.StartInfo.Verb = "runas";
    proc.Start();
}

如果您想执行notepad.exe,则只需调用此方法:

ExecuteAsAdmin("notepad.exe");

如何在管理员权限下执行弹出窗口的“是”或“否”,如果批处理文件执行需要按键关闭。 - Detective7

27

这是一个明确回答你问题的答案:如何强制我的.NET应用以管理员身份运行?

总结:

右键单击项目 -> 添加新项 -> 应用程序清单文件

然后在该文件中更改类似于以下的一行:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

编译并运行!


2
正如你所看到的,那一行代码是包含在@Hans Passant的答案中的。但是每次程序启动另一个程序时,只有那一行代码能够打开UAC窗口吗? - Jet
这对我来说完美无缺,谢谢。 - Professor Zoom

23
var pass = new SecureString();
pass.AppendChar('s');
pass.AppendChar('e');
pass.AppendChar('c');
pass.AppendChar('r');
pass.AppendChar('e');
pass.AppendChar('t');
Process.Start("notepad", "admin", pass, "");

同时也适用于ProcessStartInfo

var psi = new ProcessStartInfo
{
    FileName = "notepad",
    UserName = "admin",
    Domain = "",
    Password = pass,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};
Process.Start(psi);

5
好的,但是你为什么要使用AppendChar?不能直接写成pass="secret"吗? - Jet
7
@Jet不行,因为它需要一个SecureString而不是一个普通的字符串,而这些字符串永远不应该以未加密的形式作为一个整块在内存中可用。 - Ronan Thibaudau
假设您的密码是 password,您可以执行 for (int x = 0; x < password.Length; x++) { pass.AppendChar(password[x]); } - Mark Richman
7
@MarkRichman 这样做违背了使用SecureString的目的。-- 您应该从某个地方(例如键盘、加密源等)逐个字符地阅读它们。-- 如果您已经有一个包含数据的实际string,那么它就不安全了。 - BrainSlugs83
@MarkRichman password.ForEach(pass.AppendChar) 看起来更简洁。 - Mikael Dúi Bolinder

18

当我尝试时,这个方法是有效的。我用两个示例程序进行了双重检查:

using System;
using System.Diagnostics;

namespace ConsoleApplication1 {
  class Program {
    static void Main(string[] args) {
      Process.Start("ConsoleApplication2.exe");
    }
  }
}

using System;
using System.IO;

namespace ConsoleApplication2 {
  class Program {
    static void Main(string[] args) {
      try {
        File.WriteAllText(@"c:\program files\test.txt", "hello world");
      }
      catch (Exception ex) {
        Console.WriteLine(ex.ToString());
        Console.ReadLine();
      }
    }
  }
}

首先确认我遇到了UAC bomb:

System.UnauthorizedAccessException: 访问路径“c:\program files\test.txt”被拒绝。
// 等等。

然后在ConsoleApplication1中添加了一个包含该短语的清单:

    <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

没有炸弹。还有一个我不容易删除的文件 :) 这与在运行Vista和Win7的各种机器上进行的几次先前测试一致。启动的程序继承了启动程序的安全令牌。如果启动程序获得了管理员特权,则启动的程序也拥有这些特权。


无法删除?请详细说明,这听起来很熟悉。 - Arlen Beiler
@ArlenBeiler:他可能是指应用程序中的嵌入式清单,而不是与可执行文件并排放置在磁盘上的 .exe.manifest 文件。 - Thomas Weller
@ThomasW。我认为他指的是测试文件需要管理员权限才能删除的问题。我遇到过这种情况,通常需要进入安全选项卡并更改一些设置,如果我没记错的话。我想我最终找到了一种方法。提升的命令提示符也可能有效,但要小心。时间有时会带来答案。 :-) - Arlen Beiler

5

以下是一个在没有Windows提示的情况下以管理员身份运行进程的示例

  Process p = new Process();
  p.StartInfo.FileName = Server.MapPath("process.exe");
  p.StartInfo.Arguments = "";
  p.StartInfo.UseShellExecute = false;
  p.StartInfo.CreateNoWindow = true;
  p.StartInfo.RedirectStandardOutput = true;
  p.StartInfo.Verb = "runas";
  p.Start();
  p.WaitForExit();

这解决了我的问题!提示会从别人的答案中出现。对我来说,UseShellExecute、CreateNoWindow和RedirectStandardOutput的组合停止了这个问题。 - Blake Thingstad
4
这不能以管理员身份运行。如果您添加一个清单并请求提升的权限,它仍然无法正常工作。 - MtnManChris
它也不起作用,当我从应用程序卸载窗口服务时,它要求我输入管理员密码。 - Shyam sundar shah

3
 Process proc = new Process();                                                              
                   ProcessStartInfo info = 
                   new ProcessStartInfo("Your Process name".exe, "Arguments");
                   info.WindowStyle = ProcessWindowStyle.Hidden;
                   info.UseShellExecute =true;
                   info.Verb ="runas";
                   proc.StartInfo = info;
                   proc.Start();

在 ProcessStartInfo 中,“参数”并非必需,只有进程名称就足以启动进程。 - chirag pathak

2

使用这个方法:

public static int RunProcessAsAdmin(string exeName, string parameters)
    {
        try {
            System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
            startInfo.UseShellExecute = true;
            startInfo.WorkingDirectory = CurrentDirectory;
            startInfo.FileName = Path.Combine(CurrentDirectory, exeName);
            startInfo.Verb = "runas";
            //MLHIDE
            startInfo.Arguments = parameters;
            startInfo.ErrorDialog = true;

            Process process = System.Diagnostics.Process.Start(startInfo);
            process.WaitForExit();
            return process.ExitCode;
        } catch (Win32Exception ex) {
            WriteLog(ex);
            switch (ex.NativeErrorCode) {
                case 1223:
                    return ex.NativeErrorCode;
                default:
                    return ErrorReturnInteger;
            }

        } catch (Exception ex) {
            WriteLog(ex);
            return ErrorReturnInteger;
        }
    }

希望这能帮到您。

适用于调用 BAT 或 CMD 脚本吗? - Kiquenet

0

你可能需要将你的应用程序设置为x64应用程序。

IIS Snap In只能在64位中工作,而不能在32位中工作。从32位应用程序生成的进程似乎是32位进程,同样适用于64位应用程序。

请参考:以64位启动进程


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