本文介绍了引用函数时 PowerShell 退出事件不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 .ps1 脚本,一旦 PowerShell 会话结束,它需要一些代码来执行以进行清理.我遇到的问题的最简单再现:

I have a .ps1 script that needs some code to execute for cleanup purposes once the PowerShell session ends. Simplest reproduction of the problem I am having:

function ExitLogic(){
     Write-Host 'closing'
}
Write-Host 'started'
Register-EngineEvent `
    -SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) `
    -Action { ExitLogic }

ExitLogic 永远不会发生.如果我在 PowerShell 会话中手动使用 exit 命令不会,如果我单击 X 窗口按钮不会,如果我在 cmd.exe...我不知所措.但是,如果我将 Action 参数从引用 ExitLogic 作为函数更改为 Write-Host 'inline closed' 那么它确实有效.

The ExitLogic never happens. Not if I manually use the exit command within my PowerShell session, not if I click the X window button, not if I run PowerShell within a cmd.exe... I'm at a loss. But, if I change the Action parameter from referencing ExitLogic as a function to just Write-Host 'inline closing' then it does work.

推荐答案

tl;dr

-Action 脚本块执行时(当 引擎 退出时),ExitLogic() 函数不再在范围内.

By the time the -Action script block executes (when the engine exits), the ExitLogic() function is no longer in scope.

一般要点:

  • *.ps1 文件不在子进程中运行,因此退出脚本并不等同于整体退出 PowerShell 引擎.

  • *.ps1 files do NOT run in a child process, so exiting the script is NOT tantamount to exiting the PowerShell engine as a whole.

脚本默认在子范围中运行,因此其中定义的函数仅在脚本运行时在范围内.

scripts by default run in a child scope, so functions defined therein are only in scope while the script is running.

只有在全局范围内定义的函数才能在-Action脚本块中引用.

Only functions defined in the global scope can be referenced in an -Action script block.

-Action 脚本块执行时,许多常规 PowerShell 功能不再可用.

By the time the -Action script block executes, much of regular PowerShell functionality is no longer available.

  • 值得注意的是,无法再使用 PowerShell 自己的输出流 - 不再打印常规输出和错误消息.

  • Notably, PowerShell's own output streams cannot be used anymore - regular output and error messages no longer print.

但是,您可以使用Write-Host来产生显示输出(尽管外部调用者通过标准输出接收),但请注意如果引擎退出也关闭了当前的控制台窗口,你甚至看不到那个.一个 Read-Host 命令可以延迟关闭.

However, you can use Write-Host to produce display output (though an outside caller will receive that via stdout), but note that if the engine exiting also closes the current console window, you won't even get to see that. A Read-Host command can delay the closing.

重要:事件处理程序仅在PowerShell 本身退出会话时运行(无论是正常情况还是通过脚本 -throw 触发的终止错误) - 如果您通过关闭控制台/终端窗口间接终止 PowerShell,则事件处理程序将不会运行.

Important: The event handler only gets to run if PowerShell itself exits the session (whether normally or via a script-terminating error triggered with throw) - if you terminate PowerShell indirectly by closing the console / terminal window, the event handler won't run.

您的具体情况:

  • 鉴于 -Action 块在 engine 退出时被调用,这发生在 脚本完成之后,它确实没有看到 ExitLogic 函数,它已经超出了范围.

  • Given that the -Action block is invoked when the engine exits, which happens after completion of the script, it does not see the ExitLogic function, which has gone out of scope by then.

  • 使 ExitLogic全局 范围内可用的一种方法是点源"您的脚本(例如,..\script.ps1code>),但请注意,它仅适用于来自全局范围;需要做更多工作才能将函数从子作用域或模块作用域添加到全局作用域.
  • One way to make ExitLogic available in the global scope is to "dot-source" your script (e.g., . .\script.ps1), but note that only works from the global scope; more work is needed to add a function to the global scope from a child scope or module scope.

以下代码片段演示了这一点:

The following snippet demonstrates this:

假设存在脚本 .\script.ps1,其内容如下:

Let's assume the existence of script .\script.ps1 with the following content:

function ExitLogic {
  Write-Host 'closing'
}

Write-Host 'started'

$null = Register-EngineEvent `
 -SourceIdentifier PowerShell.Exiting `
 -Action {
   try { ExitLogic } catch { Write-Host $_ }
   Read-Host -Prompt 'Press ENTER to exit'
 }

警告:以下命令退出正在运行的 PowerShell 会话;只有 Read-Host 命令使窗口保持打开状态,允许您检查事件处理程序的 Write-Host 输出;按 ,窗口关闭.

Caveat: The following commands exit the running PowerShell session; it is only the Read-Host command that keeps the window open, allowing you to inspect the event handler's Write-Host output; on pressing , the window closes.

  • 直接调用:
# Due to direct invocation, the -Action block does NOT see ExitLogic()
PS> .\script.ps1; exit
started
The term 'ExitLogic' is not recognized as the name of a cmdlet, function,
script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Press ENTER to exit:

  • 点源调用:
  • # Thanks to dot-sourcing in the global scope, the -Action block DOES see ExitLogic()
    PS> . .\script.ps1; exit
    started
    closing
    Press ENTER to exit:
    

    这篇关于引用函数时 PowerShell 退出事件不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 22:19