提问人:Pekka 提问时间:1/11/2010 更新时间:5/4/2018 访问量:91060
Powershell 脚本卡住,从批处理文件调用时不退出
Powershell script gets stuck, doesn't exit when called from batch file
问:
我有一个连接到网站并解析其返回数据的 PowerShell 脚本(这是关于将以前上传的 SQL 文件导入网站的数据库)。PowerShell 脚本使用 ,我稍后可能会将其替换为本机函数。wget
导入过程嵌入在由名为 scriptFTP 的第三方程序执行的脚本中。
当我从单个 .bat 文件调用它时,脚本运行良好,如下所示:
powershell "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%
但是,当我从更大的 ScriptFTP 上下文中调用此 .bat 文件时,会发生以下情况:
- 执行 PowerShell 脚本。我确认了这一点,每次调用远程导入脚本时,我都会给自己发一封电子邮件。
- PowerShell 似乎没有退出,脚本执行卡住了。我仍然可以使用 Ctrl+C 取消整个过程,但以下命令永远不会执行。
当我将批处理文件更改为以下内容时:
start powershell "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%
它可以工作,在新控制台中运行 PowerShell 脚本,但我无法获取 PowerShell 返回的错误级别。
我尝试直接从 ScriptFTP 调用 PowerShell,绕过批处理文件,但结果相同:它只是卡住了。
我让 PowerShell 脚本使用或未显示的任何输出。Write-Output
Write-Host
所有程序都在同一用户 me 下运行。
有人知道该怎么做吗?
答:
尝试添加 /WAIT 参数。它将使 .bat 保持等待,直到 PowerShell 脚本完成。
START /WAIT powershell "& "C:\data\etc\run_import_script.ps1"
评论
至少在我看来,PowerShell 在以这种方式调用时具有奇怪的行为。简而言之,它不会将传递给 powershell.exe 的命令行参数视为要运行的脚本。相反,它将它们视为要运行的命令。这是因为 powershell.exe 的默认值是 -command - 请参阅 powershell.exe /?以获取更多信息。
C:\>powershell "'Hello'"
Hello
你需要做的是构造一个聪明的输入字符串来“源”你希望运行的脚本:
C:\>powershell ". .\test.ps1"
Hello, World!
至于输出,一旦你让脚本正确运行,它应该只是捕获STDOUT或任何最终适合你的脚本的问题。
完整示例
测试.bat
@echo off
powershell.exe ". .\test.ps1"
测试.ps1
"Hello, World!"
调用命令:
test.bat > test.txt
并验证是否捕获了输出:
C:\>type test.txt
Hello, World!
评论
START /WAIT powershell.exe
此变体可能适合您。
powershell -NoProfile -Command "C:\data\etc\run_import_script.ps1; exit $LASTEXITCODE" < NUL
如果这正是您文件中的内容,那是因为您的引号不匹配。Powershell 正在等待最后一个报价。
如果要捕获 powershell.exe 命令的输出,还可以使用 /B 参数强制进程在同一命令行界面中运行。
我们刚刚看到了这个问题的一个非常奇怪的例子。包含调用的批处理文件在本地运行正常,但在 msdeploy -postSync 命令的上下文中运行批处理文件时,如上所述而停止。在尝试强制 PowerShell 退出后,我们开始使用powershell.exe -command ...
process.Kill()
START /WAIT /B PowerShell.exe ..
不知道为什么这应该起作用,但它确实......
根据我的经验,PowerShell.exe 可以使用 -File 开关以可预测的方式轻松地从批处理文件或 shell 脚本中运行脚本。不需要使用“启动”命令。
要做的重要事情是附加
< nul
从批处理文件中添加到命令行。我的研究表明,PowerShell 运行通过 -File 开关指示的脚本中的命令,然后等待来自标准输入的其他 PowerShell 命令(我对 -Command 开关的简短实验演示了类似的行为)。通过将标准输入重定向到 nul,一旦 PowerShell 完成执行脚本并从标准输入中“读取文件末尾”,PowerShell 就会退出。
从 Cygwin 调用 PowerShell 时,请使用
< /dev/null
例如,我使用 shell 变量从 Cygwin 运行 PowerShell 脚本,如下所示:
PowerShell.exe -ExecutionPolicy RemoteSigned -File $_powershellscriptpath $_firstscriptparameter < /dev/null
如果您的经历与我不同,请发表评论。 -戈登
评论
我敢打赌,问题是 Powershell 进程在执行脚本后继续运行。这意味着它尚未退出,因此没有退出代码。当我尝试从 C# 运行一个 Powershell 脚本时,我遇到了类似的问题,该脚本在完成后会执行操作,但它永远不会完成......
很骇人听闻,但我找到的唯一解决方案是放在 .ps1 脚本的末尾。这会终止 PowerShell 进程(以及您不幸打开的所有 PowerShell 窗口),但似乎有效。可能也适用于您的脚本。Stop-Process -processname powershell
我遇到了确切的问题,我们试图将 power shell 脚本集成到另一个系统中,但它一直给出超时错误。可能是因为戈登·史密斯(Gordon Smith)提到的问题,他的解决方案可能会奏效。但对我来说,我更喜欢从脚本本身完全控制我的脚本,而不是依赖于调用它的方式。
$pid 内置于 PID 的变量中。下面将结束当前的 powershell 进程,并保留其他进程不变。这样,任何人都可以正常调用您的脚本,并且它将按预期工作。
Stop-Process $pid
只需将“exit”命令添加到 .ps1 脚本(或您希望的任何进程终止变体)的末尾即可。Powershell将继续在脚本末尾运行,因为它没有被告知终止(在PS或ISE中运行时,它将在脚本末尾自动终止,但在通过DOS shell运行时不会)。
我们也有类似的问题。我们想从一个软件调用一个 powershell 应用程序,该软件只有一个框可以输入“命令”和“参数”,但尽管 powershell 运行成功(我可以看到受影响的文件已更新。
最后,我的同事帮我弄清楚了 命令需要为:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
和参数:
-ExecutionPolicy unrestricted -Command "& {C:\scripts\apps\EDI\Test.ps1; [Environment]::Exit(1)}"
在我们的例子中,重要的是使用而不是.我相信 Exit 只是终止脚本,而不是关闭 Powershell 本身。[Environment]::Exit(1)
Exit 1
评论
$lastexitcode
评论