In this script, if I use a batch file, it works:
private async void cmdRunBatchFile2_Click(object sender, EventArgs e)
{
cmdRunBatchFile2.Enabled = false;
await Task.Run(() => {
var proc = new Process();
proc.StartInfo.FileName = @"test.bat";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;
if (proc.Start())
{
//do something
}
proc.WaitForExit();
});
cmdRunBatchFile2.Enabled = true;
}
However if I change it to test.ps1
, it returns this error: System.ComponentModel.Win32Exception: 'An error occurred trying to start process 'test.ps1' with working directory XYZ. The specified executable is not a valid application for this OS platform.'
System.ComponentModel.Win32Exception: 'An error occurred trying to start process 'test.ps1' with working directory XYZ. The specified executable is not a valid application for this OS platform.'
After reading .Net Core 2.0 Process.Start throws "The specified executable is not a valid application for this OS platform" , I then blindly try adding
proc.StartInfo.UseShellExecute = true;
This yields another error: System.InvalidOperationException: 'The Process object must have the UseShellExecute property set to false in order to redirect IO streams.'
Do you know why is that?
First things first: An alternative , more efficient and flexible way to execute PowerShell code from a .NET executable is to use the PowerShell SDK , which enables in-process execution with full .NET type support - see this answer for an example.
Batch files ( .bat
, .cmd
files) have special status on Windows : They are the only script -type files that the Windows API - which underlies the .NET APIs - treats as if they were directly executable, binary files , by implicitly passing such files to cmd.exe /c
for execution.
All other script files , which by definition require a scripting engine (shell) to execute, can not be executed this way, and instead you must specify their associated scripting engine / shell CLI as the executable in the .FileName
property of the System.Diagnostics.ProcessStartInfo
class, followed by the appropriate engine / shell-specific command-line parameter that requests execution of a script file, if necessary, and the script file's path itself.
.UseShellExecute = true
, you'll lose the ability to capture the launched process' output and to control its window (creation) style..UseShellExecute = true
, you can specify a script file directly in .FileName
, but there's no guarantee that it will execute , given that is the default GUI shell operation that is then performed (which never runs in the current console window), which for script files often means opening them for editing . In order to execute a .ps1
script via powershell.exe
, the Windows PowerShell CLI, use powershell.exe -file
.
Therefore:
private async void cmdRunBatchFile2_Click(object sender, EventArgs e)
{
cmdRunPs1File.Enabled = false;
await Task.Run(() =>
{
var proc = new Process();
// Specify the PowerShell CLI as the executable.
proc.StartInfo.FileName = @"powershell.exe";
// Specify arguments, i.e. the .ps1 script to invoke, via -File.
// Note: This assumes that 'test.ps1` is located in the process' current dir.
// Consider placing '-NoProfile' before '-File', to suppress
// profile loading, both for speed and a predictable execution environment.
proc.Start.Info.Arguments = @"-File test.ps1";
// !! .UseShellExecute must be false in order to be able to
// !! capture output in memory and to use .CreateNoWindow = true
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = true;
if (proc.Start())
{
//do something
}
proc.WaitForExit();
});
cmdRunPs1File.Enabled = true;
}
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.