批处理文件中的退出代码不会传播到父 powershell 脚本

2024-05-03

请注意:

c:\temp\1.cmd

@echo off
setlocal

cmd /c dir aaa
IF %ERRORLEVEL% NEQ 0 GOTO fail
GOTO end
:fail
echo - Script failed

:end
endlocal

现在,如果我在命令提示符下运行它:

C:\temp> cmd
Microsoft Windows [Version 10.0.16299.967]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\temp>c:\temp\1.cmd
 Volume in drive C has no label.
 Volume Serial Number is 4A5E-F223

 Directory of C:\temp

File Not Found
- Script failed

C:\temp>echo %errorlevel%
1

C:\temp>

现在我从 Powershell 运行它:

C:\temp> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.16299.967
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16299.967
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


C:\temp> cmd /c C:\temp\1.cmd
 Volume in drive C has no label.
 Volume Serial Number is 4A5E-F223

 Directory of C:\temp

File Not Found
- Script failed
C:\temp> $LASTEXITCODE
0
C:\temp>

据我所知,退出代码应该正确传播。那么,问题出在哪里呢?


Note: This answer was substantially rewritten after new information came to light.

来补充jazzdelightsme 的有效解决方案 https://stackoverflow.com/a/55289640/45375和一些一般指导和背景信息:

  • When calling a batch file from outside cmd.exe, such as from PowerShell, invoke it as cmd /c 'file.cmd ... & exit' or - if string interpolation is needed - as
    cmd /c "file.cmd ... & exit", which then requires escaping embedded " as `"[1]. This ensures that it behaves as it would when called from inside cmd.exe with respect to its exit code (error level), i.e. ensures that the batch file's exit code reliably becomes cmd.exe's process exit code.

    • 这个帖子 https://stackoverflow.com/q/66975883/45375详细解释了这个问题和这个晦涩难懂的解决方法。
    • Note: The simpler workaround based on call - cmd /c call file.cmd ... - works in principle, but has an unwanted side effect when (of necessity double-quoted[2]) arguments with ^ characters are passed: Due to use of call, ^ characters ("carets", strictly speaking circumflex accents, U+005E http://www.fileformat.info/info/unicode/char/5e) are invariably doubled, so that say, argument "a ^ 2", is seen by the batch file as "a ^^ 2"; it is unclear what the purpose of this behavior is, but it has seemingly always existed - see this answer https://stackoverflow.com/a/66250528/45375 for details on cmd.exe's parser.
  • Without the & exit解决方法,只有确保以下情况,您才会获得所需的行为all代码路径以下列方式之一退出 - 缺少代码路径是一个很容易犯的错误:

    • exit with no参数,它正确地中继最近执行的命令的退出代码。

      • Caveat: exit without /b立即退出cmd.exe实例作为一个整体,因此它不适合在可以交互运行或必须可从其调用的批处理文件中使用other批处理文件并将控制权返回给这些批处理文件。
    • exit /b <code> or exit <code>, where <code>表示所需的退出代码,即指定一个explicit退出代码,如 jazzdelightsme 的解决方案中所示。

      • Caveat:退出批处理文件exit /b 没有明确的<code>争论 does not传递最近执行的命令的退出代码,而不带cmd /c <batch-file> ... `& exit解决方法 - 请参阅这个答案 https://stackoverflow.com/a/66250528/45375.

附加背景信息,在上下文中你的代码:

奇怪的是,与outside调用批处理文件without & exit (or call),诸如此类的陈述if, goto, echo, and endlocal, 乃至REM(但是,奇怪的是,不是::) 重置退出代码cmd.exe稍后报告给0- 虽然inside that cmd.exe会议%ERRORLEVEL%按通常的方式设置,这意味着此类语句对当前没有影响%ERRORLEVEL% value.

所以:

  • 当您的批处理文件运行时inside cmd.exe,设置命令后面的具体语句%ERRORLEVEL% to 1 (cmd /c dir aaa),即if, goto, echo and endlocal声明,preserve这个值,以及%ERRORLEVEL%最终获得价值1退出批处理文件后。

    • 奇怪的是,错误级别仅设置after涉及批处理文件调用的语句,因此类似file.cmd || exit does not工作,因为||操作员无法识别file.cmd调用失败。这就是解决方法使用的原因&而不是||.
  • 当您的批处理文件运行时outside cmd.exe, and isn't调用与cmd /c "<batch-file> ... & exit" (or cmd /c call <batch-file> ...), 后面的语句相同%ERRORLEVEL%-setting 命令突然重置退出代码cmd.exe其本身随后向0,而不是保留批处理文件执行后%ERRORLEVEL% value.


[1] Situationally, you can get away with cmd /c <batch-file> ... `& exit, i.e. without enclosing the arguments to /c in a single, overall string, but that breaks if the batch-file path needs double-quoting and at least one double-quoted pass-through argument is also present.

[2] ^ chars. in unquoted arguments, as usual, are interpreted as cmd.exe's escape character and therefore removed.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

批处理文件中的退出代码不会传播到父 powershell 脚本 的相关文章

  • Powershell强类型环境变量

    我想设置一个强类型环境变量 当我使用 env 时它似乎 丢失 了它的类型 在原始函数中它工作正常 function Create ThisCrap Microsoft ApplicationInsights TelemetryClient
  • PowerShell 中的 SVN 输出编码

    我正在尝试在 PowerShell 脚本内的字符串中捕获 SVN 日志 在命令行上 输出的编码是正确的 但是当我将其捕获到字符串中时 它就不是正确的 PS C sandbox gt svn log r1804 https myserver
  • 如何在 PowerShell 中处理命令行参数

    处理命令行参数的 最佳 方法是什么 似乎有几个关于 最佳 方法是什么的答案 因此我陷入了如何处理像这样简单的事情上 script ps1 n name d domain AND script ps1 d domain n name 有没有一
  • 阻止单引号在 WMI 查询 powershell 中转义字符串

    我有一些使用 WMI 查询的代码 但我遇到了一个问题 我使用的变量有一个 单引号 这会导致代码出现故障 这是一个例子 path SERVER1 Mike O Leary servername path Split 2 Split 0 sha
  • 什么是@”运算符?

    我在互联网上搜索了这意味着什么 包括 and 单独 正是在这个code https gist github com jakeballard 11240204 Win32ShowWindowAsync Add Type memberDefin
  • 在 cygwin 和 powershell 中查看不同的 gem 列表

    我用的是gem listpowershell 和 cygwin 中的命令都显示不同的 gem 列表 Cygwin 显示 LOCAL GEMS bundler 1 2 3 json 1 7 5 minitest 2 12 1 rake 0 9
  • Foreach-object Parallel 块内的错误处理 - Powershell 7

    在下面的 Foreach Object Parallel 块中捕获错误的最佳方法是什么 因为将有三个单独的线程 运行空间运行并执行块中写入的代码 并且可能同时发生多个错误 异常 是否可以捕获列表 变量中的所有错误并在脚本执行结束时显示 1
  • PowerShell,使用 Start-Job 和 Start-Process 测试异步任务的性能/效率

    我很想测试 PowerShell 中异步任务的性能 有用性Start ThreadJob Start Job and Start Process 我有一个包含大约 100 个 zip 文件的文件夹 因此进行了以下测试 New Item 00
  • 如何使用 PowerShell 捕获全局击键?

    Powershell 可以监听并捕获按键吗 是否可以编写一个 PowerShell 脚本 例如自动热键 https www autohotkey com 位于托盘中并等待您按下预定义的键盘键才开始执行 并且每次按下所述键时可能不会返回而是触
  • 使用 shell_exec 将 PHP 转换为 Powershell

    如果我运行 output shell exec powershell get service dhcp 我得到了 dhcp 服务的完美输出 显示正在运行 但如果我运行 output shell exec powershell get use
  • 在 C# 中编写批处理脚本的好方法是什么?

    我想用 C 编写简单的脚本 我通常会使用 bat 或 4NT btm 文件 复制文件 解析文本 询问用户输入等等 相当简单 但在批处理文件中正确执行这些操作确实很困难 例如没有例外 我熟悉像 AxScript 这样的命令行 脚本 包装器 这
  • 防止集成终端自动打开

    每当我在 VS Code 中打开 PowerShell 脚本时 集成终端就会打开 如何防止集成终端自动打开 我搜索了 终端 的设置 但没有发现与自动启动相关的内容 VSCode 会记住您的上一次会话 因此 如果关闭终端并退出 VSCode
  • 禁止非 PowerShell 命令的输出?

    我正在运行命令 hg st 然后检查它是 LASTEXITCODE检查当前目录中 Mercurial 的可用性 我不关心它的输出 也不想将它展示给我的用户 如何抑制所有输出 成功或错误 由于 Mercurial 不是 PowerShell
  • 拖放到 Powershell 脚本

    我以为我已经找到了这个问题的答案 但我玩得越多 我就越发现它是 Powershell 的设计缺陷 我想拖放 或使用发送到机制 将多个文件和 或文件夹作为数组传递到 Powershell 脚本 测试脚本 Test ps1 param stri
  • “Microsoft.AspNet.Server.Kestrel”不包含适合入口点的静态“Main”方法

    我正在尝试运行最新的Asp Net 5 个示例 https github com aspnet Home 当前为 1 0 0 rc1 update1 来自 Windows 10 上的 powershell 我将活动和默认 DNX 设置为 C
  • 全局变量用例

    我有几个脚本和模块 它们使用全局变量来完成很多事情 我的日志记录可以采用以下三种形式之一 简洁 详细和验证 没有实际操作的详细日志记录 仅验证提供的数据 我还有许多函数 它们根据运行的上下文 用户或机器 而做出不同的响应 并且正在执行的操作
  • 如何将 .bat 文件中的变量获取到 PowerShell 脚本中?

    我正在用 PowerShell 替换 bat 脚本的部分内容 批处理文件的配置是通过以下文件完成的set适当的环境变量 我正在寻找一种方法将这些变量值加载到 ps1脚本 无需修改 bat文件 因为它们也在其他地方使用 一个例子 bat看起来
  • 使用 Powershell SQL 将数据提取到 Excel

    我想使用 powershell 将数据从 SQL Server 提取到新的 excel 文件 对于小型数据集 我的代码可以工作 但某些表的行数超过 100 000 行 这将需要很长时间 我不在 SQl 服务器中使用该实用程序的原因是因为我想
  • 抑制数组列表添加方法管道输出

    我正在使用数组列表来构建日志项序列以供稍后记录 工作起来很不错 但是 Add 方法将当前索引发送到管道 我可以通过将其发送到 null 来解决这个问题 如下所示 strings Add junk gt null 但我想知道是否有某种机制可以
  • 如何在 PowerShell 中远程执行 ELEVATED 远程脚本

    我有两台服务器 serverA Windows 2003 服务器 serverB Windows 7的 ServerA包含一个带有批处理文件 deploy bat 的文件夹 需要从提升的 powershell 提示符执行该批处理文件 在Se

随机推荐