【问题标题】:Is there a method to open CMD as Admin through a C# command?有没有办法通过 C# 命令以管理员身份打开 CMD?
【发布时间】:2015-06-04 22:04:04
【问题描述】:

我有一个小命令允许我从 CMD 查询信息,但是它需要管理员权限(不是在我的应用程序级别,而是在 CMD 级别)我走这条路的唯一原因是因为我无法获得 WMI查询我一生的 bitlocker 设置,这个项目需要离开我的办公桌。

if (bitA.Text == "Bitlocker Available")
{               
    Process cmd2 = new Process();
    cmd2.StartInfo.Verb = "runas";
    cmd2.StartInfo.FileName = "cmd.exe";
    cmd2.StartInfo.Arguments = "/c ping 8.8.8.8";
    cmd2.StartInfo.UseShellExecute = false;
    cmd2.StartInfo.RedirectStandardOutput = true;
    cmd2.StartInfo.RedirectStandardError = true;
    cmd2.Start();
    //* Read the output (or the error)
    string output2 = cmd2.StandardOutput.ReadToEnd();
    bitB.Text = output2;
    cmd2.WaitForExit();
}

【问题讨论】:

  • 您是否尝试过以管理员身份运行该应用程序?这可能使 CMD 能够以管理员身份运行(在运行帐户的权限下)。
  • 问题是 UseShellExecute 必须为真才能提升。但是 UseShellExecute 必须为 false 才能重定向。因此,您不能同时提升和重定向进程输出。您需要另一种 IPC 机制。对于某些任意命令,您可能必须将输出重定向到一个文件,然后在您的调用进程中读取它。
  • 您有没有问过有关如何在 Stack Overflow 上进行 WMI bitlocker 查找的问题,显示您尝试了什么以及遇到了什么错误?
  • 为什么大家总是使用FileName = "cmd.exe" 然后Arguments = "/c Whatever.exe whateverArg" 作为参数,为什么不直接使用FileName = "Whatever.exe"Arguments = "whateverArg"

标签: c# cmd wmi admin


【解决方案1】:

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

startInfo.Verb = "runas";

这将导致 Windows 的行为就像进程已从资源管理器中使用“以管理员身份运行”菜单命令启动一样。 UAC 将提示用户确认他们想要这样做。

编辑:我看到你已经设置了那个动词。您是在问是否可以绕过 UAC?这有点傻,否则病毒编写者等可以通过一行代码绕过安全检查。

【讨论】:

  • 在使用 runas 动词时,您必须将 UseShellExecute 设置为 true,但这会阻止您按照 OP 的要求进行重定向。
【解决方案2】:

正如我在评论中所说,问题在于“runas”动词要求 UseShellExecute 为真,但重定向要求 UseShellExecute 为假。这使问题变得有点棘手,但关键是以管理员身份启动一个进程,您可以通过某种 IPC 与之通信,然后该进程启动您要从中重定向输出的任何进程。它甚至可以是相同的可执行文件,只需打开收到的参数即可。如果我正在编写一个库,我可能会嵌入一个 shim 可执行文件作为程序集资源。下面是一个使用命名管道的简单示例:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.IO.Pipes;
using System.IO;

namespace AdminRedirect
{
    class Program
    {
        private static readonly int ProcessId = Process.GetCurrentProcess().Id;

        static void Main(string[] args)
        {
            bool isAdmin = IsAdministrator();
            Console.WriteLine("Id = {0}, IsAdmin = {1}", ProcessId, isAdmin);
            if (!isAdmin)
            {
                Console.WriteLine("Press any key to spawn the admin process");
                Console.ReadKey(intercept: true);
                string pipeName = "mypipe-" + Guid.NewGuid();
                Process cmd = new Process()
                {
                    StartInfo =
                    {
                        Verb = "runas",
                        Arguments = pipeName,
                        FileName = typeof(Program).Assembly.Location,
                        UseShellExecute = true
                    }
                };

                using (var pipeStream = new NamedPipeServerStream(pipeName))
                {
                    cmd.Start();
                    Console.WriteLine("Started {0}", cmd.Id);
                    pipeStream.WaitForConnection();
                    Console.WriteLine("Received connection from {0}", cmd.Id);
                    using (var reader = new StreamReader(pipeStream))
                    {
                        string line;
                        while((line = reader.ReadLine()) != null)
                        {
                            Console.WriteLine(line);
                        }
                    }                
                }

                Console.WriteLine("Hit any key to end");
                Console.ReadKey(intercept: true);
            }
            else
            {
                if (args.Length > 0)
                {
                    string pipeName = args[0];
                    Console.WriteLine("Opening client pipe: {0}", pipeName);
                    using (var pipeStream = new NamedPipeClientStream(pipeName))
                    {
                        pipeStream.Connect();
                        using (var writer = new StreamWriter(pipeStream))
                        {
                            StartChildProcess(writer);
                        }
                    }
                }
                else
                {
                    Console.WriteLine("We are admin and not piping, so just run");
                    StartChildProcess(Console.Out);
                    Console.WriteLine("Hit any key to end");
                    Console.ReadKey(intercept: true);
                }
            }
        }

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

        private static void StartChildProcess(TextWriter output)
        {
            var cmd = new Process()
            {
                StartInfo =
                {
                    FileName = "cmd.exe",
                    Arguments = "/c ping 8.8.8.8",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                }
            };
            cmd.Start();
            string procOutput = cmd.StandardOutput.ReadToEnd();
            output.Write("Id: {0}, Output:{1}", cmd.Id, procOutput);
        }
    }
}

【讨论】:

    【解决方案3】:

    要使用runas,您必须让UseShellExecute 为真,但是要使用任何重定向方法,您必须让UseShellExecute 为假。您不能同时拥有两者。

    如果您需要同时重定向输出和提升,您必须执行以下步骤:

    1. 使用runasUseShellExecute = true 启动您控制的另一个进程1 以生成提升的进程。
    2. 新进程以UseShellExecute = false 开始ping.exe 并重定向输出。
    3. 使用 IPC 形式 like WCF over named pipes 将提升的第二个进程的输出转发到非提升的第一个进程。

    1:它可能是您的同一个 EXE,但传递了一些特殊的命令行参数以使其处于这种新模式

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 2015-10-09
      • 1970-01-01
      相关资源
      最近更新 更多