Powershell 脚本卡住,从批处理文件调用时不退出

Powershell script gets stuck, doesn't exit when called from batch file

提问人:Pekka 提问时间:1/11/2010 更新时间:5/4/2018 访问量:91060

问:

我有一个连接到网站并解析其返回数据的 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-OutputWrite-Host

所有程序都在同一用户 me 下运行。

有人知道该怎么做吗?

Windows PowerShell的

评论

0赞 Keith Hill 1/12/2010
双引号不匹配 - 也许这是 SO 格式问题。顺便说一句,如果您使用的是 PowerShell 2.0,则应使用 -file,例如 powershell -file c:\data\etc\run_import_script.ps1
0赞 Pekka 1/12/2010
@Keith,这三个引号是故意的,看这里:stackoverflow.com/questions/2035193/......我在 1.0 上,但正在考虑更换。干杯。
0赞 Kiquenet 7/31/2012
任何带有完整源代码的最终解决方案?

答:

17赞 aphoria 1/11/2010 #1

尝试添加 /WAIT 参数。它将使 .bat 保持等待,直到 PowerShell 脚本完成。

START /WAIT powershell "& "C:\data\etc\run_import_script.ps1"

评论

2赞 Pekka 1/12/2010
干杯,这很好用,但我无法以这种方式捕获 Powershell 的输出 - 我需要将其包含在控制台输出中,以防出现错误。
0赞 aphoria 1/12/2010
不确定 PS 似乎挂起的部分。PS 脚本内部发生了什么?也许它是一些微妙的东西,只有在从脚本中调用时才会出现。我知道很奇怪,但我以前见过。另外,我认为 %ERRORLEVEL% 将具有 PowerShell.exe 的结果,但脚本的结果。因此,只要 PowerShell.exe 运行完成,它就会返回 0,而不管 .ps1 脚本中发生了什么。
0赞 Monsignor 10/6/2011
还可以添加 /MIN 参数,以在执行期间最小化 powershell 窗口。
0赞 Goyuix 1/11/2010 #2

至少在我看来,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!

评论

1赞 Pekka 1/12/2010
干杯Goyuix,这很高兴知道。可悲的是,即使这样,行为也是一样的:执行只是冻结。我没有得到任何输出。我可以随时按 Ctrl+C 完成整个过程,但什么都不会发生。如果我按照另一个答案中的建议使用,它会运行,但我无法捕获输出。很奇怪...START /WAIT powershell.exe
24赞 Jason Swager 4/3/2011 #3

此变体可能适合您。

powershell -NoProfile -Command "C:\data\etc\run_import_script.ps1; exit $LASTEXITCODE" < NUL

取自 http://thepowershellguy.com/blogs/posh/archive/2008/05/20/hey-powershell-guy-how-can-i-run-a-powershell-script-from-cmd-exe-and-return-an-errorlevel.aspx

1赞 Dennis Hostetler 4/8/2011 #4

如果这正是您文件中的内容,那是因为您的引号不匹配。Powershell 正在等待最后一个报价。

3赞 Stephen Connolly 9/26/2014 #5

如果要捕获 powershell.exe 命令的输出,还可以使用 /B 参数强制进程在同一命令行界面中运行。

我们刚刚看到了这个问题的一个非常奇怪的例子。包含调用的批处理文件在本地运行正常,但在 msdeploy -postSync 命令的上下文中运行批处理文件时,如上所述而停止。在尝试强制 PowerShell 退出后,我们开始使用powershell.exe -command ...process.Kill()START /WAIT /B PowerShell.exe ..

不知道为什么这应该起作用,但它确实......

21赞 Gordon Smith 9/30/2014 #6

根据我的经验,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

如果您的经历与我不同,请发表评论。 -戈登

评论

8赞 chillitom 5/6/2015
谢谢你,非常有用。我发现在不从 shell(并且不控制流)时有效的替代方法是使用 powershell.exe 的“-InputFormat None”参数来禁用输入流。
0赞 Deadly-Bagel 1/13/2015 #7

我敢打赌,问题是 Powershell 进程在执行脚本后继续运行。这意味着它尚未退出,因此没有退出代码。当我尝试从 C# 运行一个 Powershell 脚本时,我遇到了类似的问题,该脚本在完成后会执行操作,但它永远不会完成......

很骇人听闻,但我找到的唯一解决方案是放在 .ps1 脚本的末尾。这会终止 PowerShell 进程(以及您不幸打开的所有 PowerShell 窗口),但似乎有效。可能也适用于您的脚本。Stop-Process -processname powershell

0赞 person 2/10/2015 #8

我遇到了确切的问题,我们试图将 power shell 脚本集成到另一个系统中,但它一直给出超时错误。可能是因为戈登·史密斯(Gordon Smith)提到的问题,他的解决方案可能会奏效。但对我来说,我更喜欢从脚本本身完全控制我的脚本,而不是依赖于调用它的方式。

$pid 内置于 PID 的变量中。下面将结束当前的 powershell 进程,并保留其他进程不变。这样,任何人都可以正常调用您的脚本,并且它将按预期工作。

Stop-Process $pid
0赞 Tim 3/25/2015 #9

只需将“exit”命令添加到 .ps1 脚本(或您希望的任何进程终止变体)的末尾即可。Powershell将继续在脚本末尾运行,因为它没有被告知终止(在PS或ISE中运行时,它将在脚本末尾自动终止,但在通过DOS shell运行时不会)。

14赞 Gretski 8/26/2015 #10

我们也有类似的问题。我们想从一个软件调用一个 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

评论

1赞 Eddietec 8/30/2016
谢谢你的回答。这解决了我们使用 bamboo 代理服务器和 powershell 脚本时遇到的问题。
0赞 Stefano 11/29/2016
谢谢,也为我工作,而不是在 ps1 文件中有“退出”。
1赞 curropar 6/21/2017
伟大!我在装有 PS2 的服务器上遇到了这个问题,这已经解决了。我已将其添加到 .ps1 中,而不是 ,我可以根据需要传递它。谢谢!$lastexitcode
0赞 BuvinJ 12/29/2020
在运行 PS v2.0 的旧环境(即 Windows 7)中,我也遇到了这种需求。