【问题标题】:Why won't the "Exit" function work in my PowerShell code?为什么“退出”函数在我的 PowerShell 代码中不起作用?
【发布时间】:2021-05-18 20:28:39
【问题描述】:

当我尝试“退出”功能时。它不会关闭控制台。它什么也没做。如何更改它以使其退出控制台?

Write-Host "-------------- MENU ---------------"
Write-Host "Utility Menu"
Write-Host "1 = Help Ipconfig"
Write-Host "2 = Ipconfig"
Write-Host "3 = Notepad"
Write-Host "4 = Calculator"
Write-Host "5 = Exit"
Write-Host "-----------------------------------"

$userinput = Read-Host "Please select a menu item: "

switch ( $userinput )
{
  1 {Help Ipconfig}
  2 {ipconfig}
  3 {start notepad}
  4 {start calc.exe}
  5 {Exit}
}

【问题讨论】:

  • EXIT 关闭窗口,但仅当窗口由启动脚本的操作打开时,例如,右键单击脚本并选择“使用 powershell 运行”。我怀疑您打开了一个交互式控制台并通过输入其全名来启动脚本。在这种情况下,EXIT 关键字不会关闭控制台窗口(这会很麻烦)。
  • 试试[System.Environment]::Exit(0)

标签: powershell


【解决方案1】:

现有答案中有有用的信息,但我觉得需要概念框架

exit [...] 它不会关闭控制台。

交互式脚本想要终止整个PowerShell会话是不寻常的(这会导致控制台窗口关闭),而 exit 只会在脚本之外这样做 - 请参阅底部了解详细信息。

如果您确实打算从脚本或函数中退出整个会话[1],请使用[Environment]::Exit(0),如Colyn1337 所建议的那样。 (0 是报告进程终止的退出代码,按照惯例表示成功;当关闭交互式会话时,此退出代码可能无关紧要。)


背景资料

Language keywords 用于从 PowerShell 退出各种作用域

  • break 用于退出只是 switch 语句或循环声明(foreach/forwhiledo;也就是说,这样的语句之后,在同一范围内继续执行 - 请参阅概念性 about_Break 帮助主题。

    • 陷阱:如果您使用 breakcontinue 没有封闭循环或 switch 语句,PowerShell 会查找调用堆栈以查找此类语句并退出第一个它发现的这种陈述;如果没有,则终止当前调用堆栈;也就是说,至少封闭脚本作为一个整体终止。
      • 请注意,ForEach-Object 调用(其内置别名是 %,有些令人困惑的是 foreach),总是在管道不是循环;要“中断”传递给ForEach-Object 的脚本块,即继续下一个管道输入对象,请使用return
  • return 用于退出封闭的脚本文件(如果直接在脚本文件的顶级范围内执行)或函数 或script block ({ ... }),可选地,首先通过作为参数传递的表达式或命令输出数据(例如return 'foo' );请参阅概念性的 about_Return 帮助主题。

    • return 对脚本报告的退出代码没有影响,因此可能对整个 PowerShell 进程产生影响;只有exit 可用于设置退出代码 - 见下文。
  • exit 用于退出交互式会话封闭脚本文件,并可选择设置退出代码

    • 在脚本文件之外exit 退出交互式 PowerShell 会话作为一个整体(关闭控制台窗口)。

    • 在脚本文件内部exit 总是(仅)退出该脚本 - 即使从该脚本内的 函数 调用。

      • 注意与 return 的对比,它从一个函数中退出该函数,无论是否从脚本内部调用。
    • exit $exitCode - 其中$exitCode 代表任何整数[2] - 可用于设置脚本/会话的退出代码; 使用exitexit 0 相同

      • 由于 PowerShell 的 error handling 不是基于退出代码(与 cmd.exebash 等 shell 不同),设置退出代码主要是向外部呼叫者传达成功与失败。

      • 如果你通过 PowerShell 的CLI(例如pwsh -File script.ps1)从外部执行脚本,通过exit $exitCode 设置的退出代码也将成为进程退出代码,外部然后调用者(例如 CI 工具)可以进行检查。

        • 在会话内部,脚本通过exit $exitCode 设置的退出代码反映在automatic $LASTEXITCODE variable 中,但请注意,此变量也可以通过对外部程序的任何调用设置,以该程序的进程退出代码。
      • 有关 PowerShell 中退出代码的相关性和使用的更多信息,请参阅 this post


[1] 正如postanote's answer 所示,exit 来自一个函数,该函数已点源(直接加载到)全局范围 , 也退出整个会话。但是,最好通过[Environment]::Exit(0) 明确表示退出整个会话的异常意图。

[2] 从技术上讲,您可以将 任何 表达式或命令传递给 exit(与 return 一样,尽管表达式/命令的输出变为 data 原样),但是任何至少不能转换为整数的东西——例如exit 'not a number'——被悄悄地忽略并且 exit 0 相同。另请注意,有效整数的范围因平台而异Windows支持[int]值,即包含负数。相比之下,类 Unix 平台只支持无符号的[byte] 值,即从0255 的数字(负数转换为正数,较大的值只考虑最低字节)。

【讨论】:

    【解决方案2】:

    继续我的评论...

    代码和菜单选择的 Gif

    直接运行代码不会对退出选项执行任何操作。将脚本重构为函数确实有效。

    # Saved as Start-Menu.ps1
    Function Start-Menu {
        Clear-Host
    
        Write-Host "-------------- MENU ---------------"
        Write-Host "Utility Menu"
        Write-Host "1 = Help Ipconfig"
        Write-Host "2 = Ipconfig"
        Write-Host "3 = Notepad"
        Write-Host "4 = Calculator"
        Write-Host "5 = Exit"
        Write-Host "-----------------------------------"
    
        $userinput = Read-Host "Please select a menu item: "
    
        switch ( $userinput )
        {
          1 {Help Ipconfig}
          2 {ipconfig}
          3 {start notepad}
          4 {start calc.exe}
          5 {Exit}
        }
    }
    

    另一个关于动作的 gif。

    或者使用 Colyn1337 给你的或者这个...

        switch ( $userinput )
        {
          1 {Help Ipconfig}
          2 {ipconfig}
          3 {start notepad}
          4 {start calc.exe}
          5 {Stop-Process -Id $PID}
        }
    

    ...(获取 PowerShell 会话的当前进程 ID),因此不需要该函数,只需按原样运行脚本,并注意虽然命名空间的关闭速度比函数或 $PID 方法慢.

    【讨论】:

      【解决方案3】:

      Exit 命令实际上就像是 powershell 解析器中的一个函数。它周围有一些包装,当它执行时,Exit 并不总是意味着Exit。它通常会被解析器替换为Return

      要解决这个问题,您可以使用以下代码指示运行时终止:

      [System.Environment]::Exit(0)

      Exit 方法中的整数是您希望运行时在退出时输出的返回码。通常,除 0 以外的任何值都将被解释为错误。

      【讨论】:

      • 感谢您从您的评论中发布解决方案作为答案; +1 以获得有效的解决方案,但 exit 语言关键字 的框架并不完全正确(有关详细信息,请参阅我的答案)。
      【解决方案4】:

      使用 break 而不是 exit

      Write-Host "-------------- MENU ---------------"
      Write-Host "Utility Menu"
      Write-Host "1 = Help Ipconfig"
      Write-Host "2 = Ipconfig"
      Write-Host "3 = Notepad"
      Write-Host "4 = Calculator"
      Write-Host "5 = Exit"
      Write-Host "-----------------------------------"
      
      $userinput = Read-Host "Please select a menu item: "
      
      switch ( $userinput )
      {
        1 {Help Ipconfig}
        2 {ipconfig}
        3 {start notepad}
        4 {start calc.exe}
        5 {break}
      }
      

      【讨论】:

      • break 是退出 switch 语句的正确语句,但 OP 正在寻求关闭当前控制台窗口,即 退出当前 (PowerShell) 进程 .
      猜你喜欢
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 2014-01-23
      • 2013-08-06
      相关资源
      最近更新 更多