Is there a method to open CMD as Admin through a C# command?

南笙酒味 提交于 2019-12-24 05:05:06

问题


I have a small command that allows me to query information from CMD, however it needs admin privileges (not at my application level but at the CMD level) Only reason I am going this route is because I couldn't get WMI to query bitlocker settings for the life of me and this project needs to get off of my desk.

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();
}

回答1:


You can indicate the new process should be started with elevated permissions by setting the Verb property of your startInfo object to 'runas', as follows:

startInfo.Verb = "runas";

This will cause Windows to behave as if the process has been started from Explorer with the "Run as Administrator" menu command. The user will be prompted with the UAC to confirm they want to do it.

Edit: I see you have that verb set already. Are you asking if you can circumvent the UAC? That would be kind of silly, otherwise virus-writers and so forth could get around the security check with one line of code.




回答2:


As I said in my comment, the issue is that the "runas" verb requires UseShellExecute to be true, but redirection requires UseShellExecute to be false. This makes the problem sort of tricky, but the key is start a process as admin that you can communicate with via some kind of IPC, then this process starts whatever process you want to redirect output from. It can even be the same executable just switching on the arguments received. If I was writing a library, I would probably embed a shim executable as an assembly resource. Here is a simple example using named pipes:

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:


To use runas you must have UseShellExecute be true, however to use any of the redirect methods you must have UseShellExecute be false. You can not have both at the same time.

If you need to redirect the output and elevate at the same time you must do the following steps:

  1. Start another process you control1 using runas and UseShellExecute = true to generate a elevated process.
  2. The new process starts ping.exe with UseShellExecute = false and redirects the outputs.
  3. Use a form of IPC, like WCF over named pipes, to forward the output from your elevated 2nd process to your non elevated first process.

1: it could be your same EXE but passing some special command line arguments to put it in this new mode



来源:https://stackoverflow.com/questions/30654985/is-there-a-method-to-open-cmd-as-admin-through-a-c-sharp-command

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!