简体   繁体   中英

Converting C# Application that runs CMD commands to one that runs Powershell commands with administrative privileges

I have a Visual studio Application that runs a series of Cmd commands using the following function

public static void AdminEx(string command) //Runs an Administrative Windows Command
    {
        var proc = new System.Diagnostics.ProcessStartInfo();
        proc.UseShellExecute = true;
        proc.WorkingDirectory = @"C:\Windows\System32";
        proc.FileName = @"C:\Windows\System32\cmd.exe";
        proc.Verb = "runas";
        proc.Arguments = "/c " + command;
        proc.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        var p = System.Diagnostics.Process.Start(proc);
        p.WaitForExit();
    }

We recently updated our Code and converted to Powershell. How would I go about changing this function to accommodate for the new code. Is this still the most efficient way to go???

Just change the line:

proc.FileName = @"C:\Windows\System32\cmd.exe";

To:

proc.FileName = @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";

This will make your software open powershell.exe instead of cmd.exe, I can't tell if that is the best way to go about this but I tried here and it worked for me.

Otávio Caldonazo's helpful answer provides an effective solution, but it's worth explaining a few things:

  • Unless there are security concerns (someone having placed a nonstandard, malicious cmd.exe / powershell.exe executable in a folder listed in the %PATH% / $env:PATH environment variable that preempts the standard executables), it is simpler to use the executable file name alone, ie, just cmd.exe / powershell.exe - this also avoids problems with non-standard Windows installations whose root is not C:\\Windows .

    • Also, given that you're specifying a full path via .FileName , the .WorkingDirectory property is effectively ignored with .Verb set to runas , because .WorkingDirectory then doesn't actually set the working directory , but specifies where to find the executable , if specified by name only - however, lookups in %PATH% / $env:PATH are still performed.
  • While the /c parameter to pass a command to the shell invoked happens to work with PowerShell's CLI too, PowerShell generally use sigil - to prefix parameter names ; thus,
    -c (short for -Command ) is the better choice.

    • Additionally, given that PowerShell loads its $PROFILE initialization file by default (even when invoked with -Command or -File , even though that is generally undesirable), it's best to use -NoProfile -Command ... instead.
  • Generally - if you don't need elevation (running as an admin ) - as an alternative to the - slow - creation of a child process via powershell.exe , consider use of the PowerShell SDK (API) , which enables faster in-process execution while also enabling more fine-grained capturing of output streams (which you don't seem to be interested in in your particular scenario; while System.Diagnostics.ProcessStartInfo allows you to capture stdout and stderr output via the .RedirectStandardOutput and .RedirectStandardError properties, note that PowerShell has additional output streams ).

Based on the above, I suggest doing the following:

var proc = new System.Diagnostics.ProcessStartInfo();
proc.UseShellExecute = true;
proc.Verb = "runas";
proc.FileName = @"powershell.exe";
proc.Arguments = "-NoProfile -Command " + command;
proc.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
var p = System.Diagnostics.Process.Start(proc);
p.WaitForExit();

Or, more concisely:

using System;
using System.Diagnostics;

var proc = new ProcessStartInfo()
{
  UseShellExecute = true,
  Verb = "runas",
  WindowStyle = ProcessWindowStyle.Hidden,
  FileName = "powershell.exe",
  Arguments = "-NoProfile -Command " + command
};
Process.Start(proc).WaitForExit();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM