Powershell对cmd.exe的等待因环境而异

Powershell对cmd.exe的等待因环境而异,powershell,Powershell,请考虑powershell命令: cmd.exe "/c start notepad.exe" 使用powershell.exe(控制台),此命令在启动cmd/notepad进程后立即完成,不等待notepad/cmd退出。如果我想让它等待完成,我必须通过管道将输出设置为Out Null 使用powershell ISE,此命令将阻止执行,直到关闭记事本/cmd 此外,如果我使用System.Diagnostics.process和redirect standard output在powers

请考虑powershell命令:

cmd.exe "/c start notepad.exe"
使用powershell.exe(控制台),此命令在启动cmd/notepad进程后立即完成,不等待notepad/cmd退出。如果我想让它等待完成,我必须通过管道将输出设置为Out Null

使用powershell ISE,此命令将阻止执行,直到关闭记事本/cmd

此外,如果我使用System.Diagnostics.process和redirect standard output在powershell.exe中运行的脚本中创建一个新进程(powershell.exe),脚本现在会阻止执行,直到notepad/cmd关闭。如果我不重定向输出,它不会阻止执行

但是,如果我使用c#创建一个具有相同设置/启动信息的新进程,并使用重定向输出运行相同的脚本,它不会阻止执行

我在这里不知所措。显然,它和执行和输出的设置有关,也可能和“cmd.exe”有关。我希望有人能以不同的方式理解这些案件背后的基本情况。我知道ISE和cmd.exe不完全受支持,但我不知道为什么其他3个不一致


为什么脚本不以相同的行为运行(尤其是powershell控制台脚本),我如何让它们运行


编辑:

经过一些故障排除,我能够让所有powershell.exe版本运行相同的版本(ISE对我来说并不重要)。
cmd.exe”/c start notepad.exe“
阻止执行的奇数球是在powershell中创建新进程以使用
System.Diagnostics.process
运行powershell.exe时。如果输出被重定向(我使用
System.Diagnostics.Process
的原因是,
Start Process
不支持重定向,只支持重定向到文件),那么对Process对象调用
WaitForExit()
会导致阻塞发生


只需将
WaitForExit()
替换为
Wait Process
(以及进程ID),即可使新powershell.exe中运行的powershell脚本按预期执行,并在运行命令后退出。希望此信息与@mklement0 answer相结合,足以让其他任何人遇到类似问题。

在常规控制台和ISE中获得可预测的行为:

  • 异步启动GUI应用程序(立即返回提示符/继续执行脚本):

    • notepad.exe

    • 直接调用记事本使其异步运行,因为它是一个GUI子系统应用程序

    • 如果您仍然希望跟踪流程,并在终止时检查流程是否仍在运行以及退出代码是什么,请使用
      -PassThru
      ,这将使
      启动流程
      返回一个实例:

      • $process=启动进程-PassThru notepad.exe

        • $process.HasExited
          稍后将告诉您进程是否仍在运行
        • 退出后,
          $process.ExitCode
          会告诉您退出代码(在GUI应用程序中可能不会告诉您太多)
      • 要同步等待(在某个点):

        • 使用
          Wait Process$Process.ID
          等待(无限期)进程终止
        • 添加以秒为单位的
          -Timeout
          值以限制等待时间;如果进程未在超时时间内终止,则会报告非终止错误,导致
          $?
          反映
          $False
  • 同步启动GUI应用程序(阻止,直到应用程序终止):

    • 启动进程-等待notepad.exe

    • -Wait
      告知等待,直到创建的进程终止;这相当于
      cmd/c'start/wait notepad.exe'


请注意,对于控制台子系统应用程序(例如,
findstr.exe
),同步执行是默认的<代码>启动进程仅适用于GUI应用程序,包括显式创建新的控制台窗口以在中运行命令

要异步运行控制台应用程序或shell命令(不打开新的控制台窗口),可以使用以下选项:

  • [首选]用于启动命令,并在以后接收其输出/成功状态

    • $j=Start Job{sleep 2;'hi'}
    • 要同步等待此作业完成(并自动删除),请使用
      接收作业-等待-自动删除作业$j

    • PowerShell Core中,您可以使用更简单的
      &语法(如中所示
      类似于POSIX的Unix shell,如
      bash
      )代替
      Start Job
      ;e、 g:

      • $j=&{sleep 2;'hi!'}&
  • [不建议]您可以使用类似于
    启动进程-非Windows powershell-Args…
    的方法,但这是不明智的:

    • 通过
      Start Process
      将shell命令传递给
      powershell
      ,需要基于模糊规则的复杂引用-请参阅我的背景信息
    • 默认情况下,由application/shell命令生成的任何stdout和stderr输出都将异步地到达当前控制台,并与您正在交互执行的操作交织在一起
    • 虽然您可以使用
      -RedirectStandardOutput
      -RedirectStandardError
      (以及通过
      -RedirectStandardInput
      的stdin输入)将这些流重定向到文件,并且您可以使用
      -PassThru
      获取流程信息对象以确定流程的状态和退出代码,
      启动作业