我有一个.ps1
脚本,一旦PowerShell会话结束,需要执行一些代码以进行清理。最简单地复制我遇到的问题:
function ExitLogic(){
Write-Host 'closing'
}
Write-Host 'started'
Register-EngineEvent `
-SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) `
-Action { ExitLogic }
ExitLogic永远不会发生。如果我在PowerShell会话中手动使用exit
命令,而不是单击X
窗口按钮,如果我在cmd.exe
内运行PowerShell,则不是...我在失利。 但是,如果我将Action
参数从引用ExitLogic
作为函数更改为Write-Host 'inline closing'
,那么它确实可以正常工作。
答案 0 :(得分:4)
<强> TL;博士强>
当-Action
脚本块执行时(引擎退出时),ExitLogic()
函数不再在范围内。
关于Ethan的注意事项:我可能已经意识到的一些要点 - 为了未来的读者的利益,我在这里拼写出来。
一般要点:
*.ps1
文件不会在子进程中运行 ,因此退出脚本并不等于退出PowerShell 引擎作为一个整体。
脚本在子范围 中运行,因此在脚本运行时,其中定义的函数仅在范围内。
只有全局范围内定义的功能才能在-Action
脚本块中引用。
当-Action
脚本块执行时,大部分常规PowerShell功能不再可用。从v6.2.0开始编写 < / p>
值得注意的是,PowerShell自己的输出流不能再使用 - 不再打印常规输出和错误消息。
但是,你可以 使用Write-Host
生成显示输出(虽然外部来电者将会通过stdout接收,但请注意如果引擎退出也会关闭当前控制台窗口,您甚至不会看到它。 A Read-Host
命令可以延迟结束。
Microsoft.PowerShell.Utility
模块的命令可用,而所有其他模块都已卸载 - 请参阅this GitHub issue。 重要:事件处理程序只有在PowerShell本身退出会话时才能运行 (无论是正常还是通过脚本 - 使用throw
触发终止错误 - 如果通过关闭控制台/终端窗口间接终止PowerShell ,事件处理程序将无法运行。
您的具体案例:
鉴于在引擎退出时调用-Action
块,在完成脚本后发生,它 not 请参阅ExitLogic
函数,该函数已超出范围。
ExitLogic
的一种方法是使用#dot; dot-source&#34;您的脚本(例如. .\script.ps1
),但请注意,只有来自全局范围;从子范围或模块范围向全局范围添加函数需要做更多的工作。以下代码段演示了这一点:
让我们假设脚本.\script.ps1
存在以下内容:
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'
}
注意:正如Get-Help Register-EngineEvent
所述,支持以下-SourceIdentifier
值:PowerShell.Exiting
,PowerShell.OnIdle
和PowerShell.OnScriptBlockInvoke
,它们对应于enum- 的值,如 [System.Management.Automation.PSEngineEvent]
class;明确地使用后者(如在OP中)可以提供更多的类型安全性,但输入也更麻烦。
警告:以下命令退出正在运行的PowerShell会话;只有Read-Host
命令才能让窗口保持打开状态 - 允许您检查事件处理程序的Write-Host
输出 - 并按 Enter 窗口关闭
# 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: