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
.
.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.
$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.