winforms 为什么process.start()只接受批处理,而不接受PowerShell脚本?

cmssoen2  于 2022-12-14  发布在  Shell
关注(0)|答案(1)|浏览(185)

在此脚本中,如果我使用批处理文件,它将工作:

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

但是,如果我将其更改为test.ps1,则会返回以下错误: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.'
在阅读.Net Core 2.0 Process.Start throws "The specified executable is not a valid application for this OS platform"之后,我接着盲目地尝试添加

proc.StartInfo.UseShellExecute = true;

这会产生另一个错误:System.InvalidOperationException: 'The Process object must have the UseShellExecute property set to false in order to redirect IO streams.'
你知道这是为什么吗?

j9per5c4

j9per5c41#

首先要做的是:从.NET可执行文件执行PowerShell代码的一种替代、更高效、更灵活的方法是使用PowerShell SDK***,它支持 * 进程内执行 具有 * 完整的.NET类型支持**-有关示例,请参见this answer

批处理文件(.bat.cmd文件)在Windows上具有 * 特殊状态*:它们是Windows API(作为.NET API的基础)将其视为 * 可直接执行的二进制文件 * 的唯一 * 脚本 * 类型文件,方法是 * 隐式 * 将此类文件传递给cmd.exe /c执行。
所有其他脚本文件,根据定义需要脚本 * 引擎 (shell), 不能 * 以这种方式执行,必须在System.Diagnostics.ProcessStartInfo类的.FileName属性中将其关联的脚本引擎/ shell CLI指定为可执行文件,后跟请求执行脚本文件的相应引擎/shell特定命令行参数,如果需要,还可以包含脚本文件本身的路径。

  • 注意事项:
  • 如果您使用.UseShellExecute = true,您将失去捕获已启动进程的输出和控制其窗口(创建)样式的能力。
  • 使用.UseShellExecute = true,您 * 可以 * 直接在.FileName中指定脚本文件,但不能保证它会 * 执行 *,因为这是随后执行的 * 默认GUI shell操作 *(不会在 * 当前 * 控制台窗口中运行),这对于脚本文件通常意味着 * 打开它们进行编辑 *。

要通过powershell.exe(Windows PowerShell CLI)执行.ps1脚本,请使用powershell.exe -file
因此:

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

相关问题