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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2041799/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:02:35  来源:igfitidea点击:

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

windowspowershell

提问by Pekka

I have a PowerShell script that connects to a web site, and parses its returned data (It's about importing a previously uploaded SQL file into the web site's data base). The PowerShell script uses wget, something I may replace by a native function later.

我有一个连接到网站的 PowerShell 脚本,并解析其返回的数据(这是关于将以前上传的 SQL 文件导入网站的数据库)。PowerShell 脚本使用wget,稍后我可能会用本机函数替换它。

The import process is embedded in a script that is executed by a 3rd party program called scriptFTP.

导入过程嵌入在由名为scriptFTP的第 3 方程序执行的脚本中。

The script runs fine when I call it from a single .bat file like so:

当我从单个 .bat 文件调用它时,脚本运行良好,如下所示:

powershell  "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%

However, when I call this .bat file from within the greater ScriptFTP context, the following happens:

但是,当我从更大的 ScriptFTP 上下文中调用这个 .bat 文件时,会发生以下情况:

  • The PowerShell script is executed. I confirmed this my sending myself an E-Mail each time the remote import script got called.
  • PowerShell doesn't seem to exit, and script execution gets stuck. I can still cancel the whole thing using Ctrl+C but the following commands never get executed.
  • 执行PowerShell 脚本。每次调用远程导入脚本时,我都会向自己发送一封电子邮件,确认这一点。
  • PowerShell 似乎没有退出,并且脚本执行卡住了。我仍然可以使用 Ctrl+C 取消整个操作,但以下命令永远不会执行。

When I change the batch file to the following:

当我将批处理文件更改为以下内容时:

start powershell  "& "C:\data\etc\run_import_script.ps1"
exit %ERRORLEVEL%

it works, running the PowerShell script in a new console, but I can't grab the error level that PowerShell returns.

有效,在新控制台中运行 PowerShell 脚本,但我无法获取 PowerShell 返回的错误级别。

I have tried calling PowerShell from ScriptFTP directly, bypassing the batch file, but with the same result: It just gets stuck.

我尝试直接从 ScriptFTP 调用 PowerShell,绕过批处理文件,但结果相同:它只是卡住了。

Any output I have the PowerShell script do using Write-Outputor Write-Hostis not displayed.

我有 PowerShell 脚本使用Write-Output或未Write-Host显示的任何输出。

All programs run under the same user, me.

所有程序都在同一个用户下运行,我。

Does anybody have any ideas what to do?

有没有人有任何想法该怎么做?

采纳答案by aphoria

Try adding the /WAIT parameter. It will keep the .bat waiting until the PowerShell script completes.

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

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

回答by Gordon Smith

From my experience, PowerShell.exe can easily run scripts from within a batch file or shell script in a predictable way using the -File switch. One does not need to use the Start command.

根据我的经验,PowerShell.exe 可以使用 -File 开关以可预测的方式轻松地从批处理文件或 shell 脚本中运行脚本。一个不需要使用启动命令。

The important thing to do is to append

重要的事情是追加

< nul

to the command line from within a batch file. My research has shown that PowerShell runs the commands in the script indicated through the -File switch and then waits for additional PowerShell commands from the standard input(my brief experimentation with the -Command switch demonstrated similar behavior). By redirecting the standard input to nul, once PowerShell finishes executing the script and "reads end-of-file" from the standard input, PowerShell exits.

从批处理文件中到命令行。我的研究表明,PowerShell 运行通过 -File 开关指示的脚本中的命令,然后等待来自标准输入的其他 PowerShell 命令(我对 -Command 开关的简短实验证明了类似的行为)。通过将标准输入重定向到 nul,一旦 PowerShell 完成执行脚本并从标准输入“读取文件结尾”,PowerShell 就会退出。

When invoking PowerShell from Cygwin, use

从 Cygwin 调用 PowerShell 时,使用

< /dev/null

For example, I've run PowerShell scripts from Cygwin using shell variables, like this:

例如,我使用 shell 变量从 Cygwin 运行 PowerShell 脚本,如下所示:

PowerShell.exe -ExecutionPolicy RemoteSigned -File $_powershellscriptpath $_firstscriptparameter < /dev/null

Please post a comment if your experience varied from mine. - Gordon

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

回答by user2733913

We had a similar issue. We wanted to call a powershell appfrom a piece of software that just had a box to enter "Command" and "Parameters" but although the powershellran successfully (I could see the affected file updated.)

我们有一个类似的问题。我们想从一个只有一个框来输入“命令”和“参数”的软件中调用一个powershell 应用程序,但尽管powershell运行成功(我可以看到受影响的文件已更新。)

Finally my coworker helped me figure it out Command needs to be:

最后我的同事帮我弄清楚命令需要是:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe 

And Parameters:

和参数:

-ExecutionPolicy unrestricted -Command "& {C:\scripts\apps\EDI\Test.ps1; [Environment]::Exit(1)}"

In our case it was important to use [Environment]::Exit(1)rather than Exit 1. I believe Exitwas simply terminating the script, not closing Powershellitself.

在我们的例子中,使用[Environment]::Exit(1)而不是Exit 1. 我相信Exit只是终止脚本,而不是关闭Powershell本身。

回答by Stephen Connolly

If you want to capture the output of the powershell.exe commands then you can also use the /B parameter to force the process to run in the samecommand shell.

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

We've just seen a very odd instance of this problem. A batch file containing the call powershell.exe -command ...ran fine locally but stalled as described above when the batch file was run in the context of an msdeploy -postSync command. After experimenting with process.Kill()to force PowerShell to quit, we lit on the use of START /WAIT /B PowerShell.exe ..

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

No idea why this should work, but it does ...

不知道为什么这应该有效,但它确实......

回答by WebWeasel

IF that is exactly what's in your file it's because you have mismatched quotes. Powershell is waiting for the last quote.

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

回答by Goyuix

PowerShell has, at least what I consider, strange behavior when being invoked in this manner. In short, it doesn't treat the command line arguments being passed to powershell.exe as scripts to run. Instead, it treats them as command to run. This is because the default for powershell.exe is -command- see powershell.exe /? for additional info.

以这种方式调用 PowerShell 时,至少在我看来,它具有奇怪的行为。简而言之,它不会将传递给 powershell.exe 的命令行参数视为要运行的脚本。相反,它将它们视为要运行的命令。这是因为 powershell.exe 的默认值是-command- 请参阅 powershell.exe /? 了解更多信息。

C:\>powershell "'Hello'"
Hello

What you will need to do, is construct a clever input string to "source" the script you wish to run:

您需要做的是构造一个巧妙的输入字符串来“源”您希望运行的脚本:

C:\>powershell ". .\test.ps1"
Hello, World!

As for the output, once you get the script running correctly, it should just be a matter of capturing STDOUT or whatever ends up fitting with your script.

至于输出,一旦您使脚本正确运行,它应该只是捕获 STDOUT 或任何最终适合您的脚本的问题。

Full Example

完整示例

test.bat

测试.bat

@echo off
powershell.exe ". .\test.ps1"

test.ps1

测试.ps1

"Hello, World!"

Invoke the command:

调用命令:

test.bat > test.txt

And verify the output was captured:

并验证输出是否被捕获:

C:\>type test.txt
Hello, World!

回答by Deadly-Bagel

The problem I bet is that the Powershell process continutes to run after executing the script. This means it has not exited and therefore there is no exit code. I'm having a similar problem when trying to run a Powershell script from C# that does stuff when finished, except it never finishes...

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

Hacky, but the only solution I've found is to put Stop-Process -processname powershellat the end of the .ps1 script. This kills off the PowerShell process (and all PowerShell windows you have open unfortunately) but seems to work. Might work for your script as well.

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

回答by person

I had the exact issue, we were trying to integrate power shell scripts into another system and it kept giving a timeout error. Probably because of the issue mentioned by Gordon Smith, his solution might work. But to me I prefer to have complete control of my script from within the script itself and not depend on the way in which it is called.

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

$pid is built in variable with the PID. The below will end the current powershell process and leave the others intact. This way anyone can call your script as normal and it will work as expected.

$pid 与 PID 一起内置于变量中。下面将结束当前的 powershell 进程并保持其他进程完好无损。这样任何人都可以正常调用您的脚本,它会按预期工作。

Stop-Process $pid

回答by Tim

you can simply add an 'exit' command to the end of the .ps1 script (or any variant of process termination that you wish). Powershell will continue to run at the end of the script as it has not been told to terminate (when run in PS or ISE it will auto-terminate at the end of the script but not when run through the DOS shell).

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