使用正确的退出代码报告从PowerShell调用批处理文件,同时避免插入符号加倍
我怀疑没有好的解决办法,但也许我忽略了一些事情: 我想要的是一种方法:使用正确的退出代码报告从PowerShell调用批处理文件,同时避免插入符号加倍,powershell,batch-file,cmd,parameter-passing,exit-code,Powershell,Batch File,Cmd,Parameter Passing,Exit Code,我怀疑没有好的解决办法,但也许我忽略了一些事情: 我想要的是一种方法: (a) 从PowerShell调用批处理文件的方式应能在PowerShell的automatic$LASTEXITCODE变量中可靠地反映其隐式或显式退出代码 值得注意的是,调用退出的批处理文件(例如,whoami-nosuch | | exit/b)应导致$LASTEXITCODE反映whoami的退出代码,即1。当您从PowerShell调用批处理文件(按名称或路径)时,情况并非如此:退出代码为0(相反,在cmd.e
- (a) 从PowerShell调用批处理文件的方式应能在PowerShell的automatic
变量中可靠地反映其隐式或显式退出代码$LASTEXITCODE
- 值得注意的是,调用退出的批处理文件(例如,
)应导致whoami-nosuch | | exit/b
反映$LASTEXITCODE
的退出代码,即whoami
。当您从PowerShell调用批处理文件(按名称或路径)时,情况并非如此:退出代码为1
(相反,在0
会话中cmd.exe
设置为%ERRORLEVEL%
)1
- 还请注意,调用应该与PowerShell的输出流保持集成,因此我不寻找基于的解决方案
- 此外,我不知道或无法控制调用的批处理文件-我正在寻找一个通用的解决方案
- 值得注意的是,调用退出的批处理文件(例如,
- (b) 没有以任何方式更改传递给批处理文件的双引号参数,也没有以任何方式修改
的行为;值得注意的是:cmd.exe
字符不应加倍(见下文)^
- 使用
启用延迟扩展不是一个选项/V:ON
我知道如何解决(a)的唯一方法是通过
cmd/c call
调用批处理文件
不幸的是,这违反了要求(b),因为在参数中使用call
似乎总是将^
字符加倍。(相反,不使用call
则无法可靠地报告退出代码)
有没有办法同时满足这两个要求
请注意,PowerShell在这里只是信使:问题在于cmd.exe
,任何从cmd.exe
会话外部调用批处理文件的人都会面临同样的问题
示例(PowerShell代码): 输出应为:
["a ^ 2"]
1
然而,在现实中,退出代码并未报告:
["a ^ 2"]
0 # !! BROKEN
如果我使用cmd/c调用。\test.cmd
进行调用,则退出代码是正确的,但^
字符会加倍:
PS> cmd /c call .\test.cmd "a ^ 2"; $LASTEXITCODE
["a ^^ 2"] # !! BROKEN
1 # OK
我不知道为什么会这样,但它确实:
cmd/c'.\test.cmd“a^2”退出(&E)
$LASTEXITCODE
输出:
[“a^2”]
1.
在中找到了有效的解决方法,这是我的荣幸;让我补充一些背景信息和指导:
- 首先,明确地说,不需要任何变通办法
cmd.exe的行为显然是一个bug
——即cmd/c.\test.cmd“a^2”| | | exit”
而不是| |
——也是一种有效的解决方法。事实上,只有对命令进行无条件排序的&
,才起作用,这表明即使是&
(批处理文件的内部故障状态)在同一条语句中还不为人所知(仅在之后),这似乎是该错误的另一种表现形式cmd.exe
- 为什么作为同一语句的一部分,批处理文件调用之后的显式
调用会正确地传递批处理文件的(零或非零)退出代码,这是任何人的猜测,但似乎是可行的exit
- 为什么作为同一语句的一部分,批处理文件调用之后的显式
- 幸运的是,对于不包含显式
/exit/b
调用的批处理文件中的相关退出代码问题,该解决方法也很有效-请参阅exit
- 在PowerShell中,传递单个命令字符串的替代方法是传递单个参数并将
字符转义为&
(使用`&
,PowerShell的转义字符“backtick”),以防止PowerShell对其进行解释(将其引用为`
也可以):`&
- 在不涉及shell的环境中,例如从任务调度器启动时,
-不需要转义`
(且不得使用)&
cmd.exe
命令括在引号中,这样可以更容易地传递(a)单独需要双引号的参数,以及(b)涉及对PowerShell变量和/或表达式的引用的参数,因为后者需要使用“…”
,而不是“…”
:
# Passing *individual* arguments makes double-quoting easier.
PS> cmd /c .\test.cmd "Version = $($PSVersionTable.PSVersion)" `& exit; $LASTEXITCODE
["Version = 7.2.0-preview.4"]
1
在这种情况下,使用整个for-cmd.exe
命令的引号会很麻烦,因为需要转义特定于参数的“
字符:
# Embedded double quotes must now be `-escaped.
PS> cmd /c ".\test.cmd `"Version = $($PSVersionTable.PSVersion)`" & exit"
["Version = 7.2.0-preview.4"]
1
模块(由我编写;使用
安装模块本机
进行安装)带有功能ie
,它:
- 自动应用上述解决方法
- 通常补偿由于PowerShell的断开参数传递到外部程序而引起的问题(请参阅)
希望函数
ie
所做的将成为PowerShell本身的一部分,作为即将推出的(在PowerShell v7.2中)PSNativeCommandArgumentPassing
实验功能的一部分,该功能旨在作为中断参数传递的选择性加入修复-请参见这对我来说很有效:cmd'/c.\test.cmd“a^2“&退出/b”
。它从测试批处理文件返回正确的输出,如果我在那里乱说,我会在$LASTEXITCODE
(MSG\u DIR\u BAD\u COMMAND\u或\u file
)中得到9009
。太好了,@beatcracker-请将其作为答案发布,我会接受它。我已经试过了| |退出/b
,它应该可以工作;我甚至没有想到尝试&exit/b
——这表明cmd.exe
本身没有意识到批处理
# Passing *individual* arguments makes double-quoting easier.
PS> cmd /c .\test.cmd "Version = $($PSVersionTable.PSVersion)" `& exit; $LASTEXITCODE
["Version = 7.2.0-preview.4"]
1
# Embedded double quotes must now be `-escaped.
PS> cmd /c ".\test.cmd `"Version = $($PSVersionTable.PSVersion)`" & exit"
["Version = 7.2.0-preview.4"]
1
# After having run Install-Module Native:
# Use of function `ie` applies the workaround behind the scenes.
PS> ie .\test.cmd "Version = $($PSVersionTable.PSVersion)"; $LASTEXITCODE
["Version = 7.2.0-preview.4"]
1