如何防止主机退出和 return 退出代码?
How to prevent exit of host and return exit code?
Ansgar Wiechers 的回答在启动新的 PowerShell 进程时效果很好。 这适用于 cmd.exe 和 powershell.exe。
C:>type .\exit1.ps1
function ExitWithCode($exitcode) {
$host.SetShouldExit($exitcode)
exit $exitcode
}
ExitWithCode 23
在 cmd.exe 互动中 shell。
C:>powershell -NoProfile -Command .\exit1.ps1
C:>echo %ERRORLEVEL%
23
C:>powershell -NoProfile -File .\exit1.ps1
C:>echo %ERRORLEVEL%
23
在 PowerShell 交互中 shell。
PS C:>powershell -NoProfile -Command .\exit1.ps1
PS C:>$LASTEXITCODE
23
PS C:>powershell -NoProfile -File .\exit1.ps1
PS C:>$LASTEXITCODE
23
然而...运行现有交互式 PowerShell 主机中的 .ps1 脚本将完全退出主机。
PS C:>.\exit1.ps1
<<<poof! gone! outahere!>>>
如何防止它退出主机 shell?
How can I prevent it from exiting the host shell?
您可以检查当前 运行 PowerShell 进程是否是另一个 PowerShell 父进程的子进程,并且只有在该条件为真时才调用 $host.SetShouldExit()
。例如:
function ExitWithCode($exitcode) {
# Only exit this host process if it's a child of another PowerShell parent process...
$parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId
$parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name
if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) }
exit $exitcode
}
ExitWithCode 23
希望对您有所帮助。
不要使用$host.SetShouldExit()
:它不是由用户代码调用的。
相反,PowerShell 在内部 使用它来响应用户代码 .
中的 exit
语句
只需在您的 exit1.ps1
脚本中直接使用 exit 23
,它将执行您想要的操作:
当 运行 在 PowerShell 会话中 时,脚本将设置退出代码 23
而不退出整个 PowerShell 进程;之后使用$LASTEXITCODE
查询。
.\exit.ps1; $LASTEXITCODE # -> 23
当运行 通过PowerShell CLI:
和-File
,脚本设置的退出代码自动成为PowerShell进程的退出代码,调用者可以查看;当从 cmd.exe
调用时,%ERRORLEVEL%
反映退出代码。
powershell -File .\exit.ps1
:: This outputs 23
echo %ERRORLEVEL%
与 -Command
、需要额外的工作,因为 PowerShell 然后只需 将任何非零退出代码映射到 1
,这会导致特定的退出代码丢失;为了弥补这一点,只需 执行 exit $LASTEXITCODE
作为最后一条语句 :
powershell -Command '.\exit.ps1; exit $LASTEXITCODE'
:: This outputs 23
echo %ERRORLEVEL%
有关 PowerShell 如何设置退出代码的更多信息,。
如果:
您无法控制通过 CLI 调用脚本的方式,但必须确保报告正确的退出代码,即使通过 -Command
调用脚本也是如此,
和您愿意承担使用$host.SetShouldExit()
的风险,即使它不是为直接使用而设计的,
您可以尝试以下方法:
function ExitWithCode($exitcode) {
if ([Environment]::CommandLine -match ( # Called via the CLI? (-File or -Command)
' .*?\b' +
[regex]::Escape([IO.Path]::GetFileNameWithoutExtension($PSCommandPath)) +
'(?:\.ps1\b| |$)')
) {
# CAVEAT: While this sets the exit code as desired even with -Command,
# the process terminates instantly.
$host.SetShouldExit($exitcode)
}
else {
# Exit normally, which in interactive session exits the script only.
exit $exitcode
}
}
ExitWithCode 23
函数在进程命令行上查找执行脚本的文件名,以检测是否通过 CLI、自动 $PSCommandPath
变量,其中包含脚本的完整路径。
如果是这样,应用 $host.SetShouldExit()
调用以确保即使在通过 -Command
.
调用的情况下也按预期设置退出代码
请注意,这相当于有效 内部 .SetShouldExit()
方法的 重新利用 。
令人惊讶的是,即使在 -Command
字符串中的脚本调用之后出现其他命令,这种重新利用也能奏效,但请注意,这总是意味着真正最后一个命令的成功状态——如果它不是脚本调用的话——是有效忽略。
这种方法并非万无一失[1],但在实践中可能效果很好。
[1]
- 可能存在 误报,假设只查找文件 name,没有扩展名(因为
-Command
允许省略被调用脚本的 .ps1
扩展名)。
- 如果脚本是通过另一个脚本或通过别名调用的,则可能存在 漏报。
Ansgar Wiechers 的回答在启动新的 PowerShell 进程时效果很好。
C:>type .\exit1.ps1
function ExitWithCode($exitcode) {
$host.SetShouldExit($exitcode)
exit $exitcode
}
ExitWithCode 23
在 cmd.exe 互动中 shell。
C:>powershell -NoProfile -Command .\exit1.ps1
C:>echo %ERRORLEVEL%
23
C:>powershell -NoProfile -File .\exit1.ps1
C:>echo %ERRORLEVEL%
23
在 PowerShell 交互中 shell。
PS C:>powershell -NoProfile -Command .\exit1.ps1
PS C:>$LASTEXITCODE
23
PS C:>powershell -NoProfile -File .\exit1.ps1
PS C:>$LASTEXITCODE
23
然而...运行现有交互式 PowerShell 主机中的 .ps1 脚本将完全退出主机。
PS C:>.\exit1.ps1
<<<poof! gone! outahere!>>>
如何防止它退出主机 shell?
How can I prevent it from exiting the host shell?
您可以检查当前 运行 PowerShell 进程是否是另一个 PowerShell 父进程的子进程,并且只有在该条件为真时才调用 $host.SetShouldExit()
。例如:
function ExitWithCode($exitcode) {
# Only exit this host process if it's a child of another PowerShell parent process...
$parentPID = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$PID" | Select-Object -Property ParentProcessId).ParentProcessId
$parentProcName = (Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$parentPID" | Select-Object -Property Name).Name
if ('powershell.exe' -eq $parentProcName) { $host.SetShouldExit($exitcode) }
exit $exitcode
}
ExitWithCode 23
希望对您有所帮助。
不要使用$host.SetShouldExit()
:它不是由用户代码调用的。
相反,PowerShell 在内部 使用它来响应用户代码 .
exit
语句
只需在您的 exit1.ps1
脚本中直接使用 exit 23
,它将执行您想要的操作:
当 运行 在 PowerShell 会话中 时,脚本将设置退出代码
23
而不退出整个 PowerShell 进程;之后使用$LASTEXITCODE
查询。.\exit.ps1; $LASTEXITCODE # -> 23
当运行 通过PowerShell CLI:
和
-File
,脚本设置的退出代码自动成为PowerShell进程的退出代码,调用者可以查看;当从cmd.exe
调用时,%ERRORLEVEL%
反映退出代码。powershell -File .\exit.ps1 :: This outputs 23 echo %ERRORLEVEL%
与
-Command
、需要额外的工作,因为 PowerShell 然后只需 将任何非零退出代码映射到1
,这会导致特定的退出代码丢失;为了弥补这一点,只需 执行exit $LASTEXITCODE
作为最后一条语句 :powershell -Command '.\exit.ps1; exit $LASTEXITCODE' :: This outputs 23 echo %ERRORLEVEL%
有关 PowerShell 如何设置退出代码的更多信息,
如果:
您无法控制通过 CLI 调用脚本的方式,但必须确保报告正确的退出代码,即使通过
-Command
调用脚本也是如此,和您愿意承担使用
$host.SetShouldExit()
的风险,即使它不是为直接使用而设计的,
您可以尝试以下方法:
function ExitWithCode($exitcode) {
if ([Environment]::CommandLine -match ( # Called via the CLI? (-File or -Command)
' .*?\b' +
[regex]::Escape([IO.Path]::GetFileNameWithoutExtension($PSCommandPath)) +
'(?:\.ps1\b| |$)')
) {
# CAVEAT: While this sets the exit code as desired even with -Command,
# the process terminates instantly.
$host.SetShouldExit($exitcode)
}
else {
# Exit normally, which in interactive session exits the script only.
exit $exitcode
}
}
ExitWithCode 23
函数在进程命令行上查找执行脚本的文件名,以检测是否通过 CLI、自动 $PSCommandPath
变量,其中包含脚本的完整路径。
如果是这样,应用 $host.SetShouldExit()
调用以确保即使在通过 -Command
.
调用的情况下也按预期设置退出代码
请注意,这相当于有效 内部 .SetShouldExit()
方法的 重新利用 。
令人惊讶的是,即使在 -Command
字符串中的脚本调用之后出现其他命令,这种重新利用也能奏效,但请注意,这总是意味着真正最后一个命令的成功状态——如果它不是脚本调用的话——是有效忽略。
这种方法并非万无一失[1],但在实践中可能效果很好。
[1]
- 可能存在 误报,假设只查找文件 name,没有扩展名(因为
-Command
允许省略被调用脚本的.ps1
扩展名)。 - 如果脚本是通过另一个脚本或通过别名调用的,则可能存在 漏报。