从 PowerShell 调用批处理文件,并提供正确的退出代码报告,同时避免插入符号重复

mkl*_*nt0 7 powershell cmd batch-file exit-code parameter-passing

我怀疑没有好的解决方案,但也许我忽略了一些事情:

我所追求的是一种方法:

  • (a) 从 PowerShell 调用批处理文件,其方式可以在 PowerShell 自动变量中稳健地$LASTEXITCODE反映其(隐式或显式)退出代码。

    • 值得注意的是,调用以 , 退出的批处理文件whoami -nosuch || exit /b应该会导致$LASTEXITCODE反映 的whoami退出代码,即1当您从 PowerShell 调用批处理文件(按名称或路径)时,情况并非如此:退出代码为0(相反,在cmd.exe会话内部设置为%ERRORLEVEL% 1

    • 另请注意,调用应与 PowerShell 的输出流保持集成,因此我并不是寻找基于System.Diagnostics.Process.

    • 此外,我知道或无法控制调用的批处理文件 - 我正在寻找通用的解决方案。

  • (b) 传递给批处理文件的双引号参数不会以任何方式被更改,并且cmd.exe的行为不会以任何方式被修改;尤其:

    • ^字符不应该(见下文)。
    • 启用延迟扩展不是一个/V:ON选项

我知道如何解决(a)的唯一方法是通过调用批处理文件cmd /c call

不幸的是,这违反了要求 (b),因为在参数中使用call看似总是双倍的^字符。(并且,相反,使用callthen 不会可靠地报告退出代码)。

有没有办法同时满足要求呢?

请注意,PowerShell 只是这里的信使:问题在于cmd.exe,任何从会话外部调用批处理文件的人cmd.exe都会面临同样的问题。


示例(PowerShell 代码):

# Create a (temporary) batch file that echoes its arguments,
# provokes an error, and exits with `exit /b` *without an explicit argument*.
'@echo off & echo [%*] & whoami -nosuch 2>NUL || exit /b' | Set-Content test.cmd

# Invoke the batch file and report the exit code.
.\test.cmd "a ^ 2"; $LASTEXITCODE
Run Code Online (Sandbox Code Playgroud)

输出应该是

["a ^ 2"]
1
Run Code Online (Sandbox Code Playgroud)

然而,实际上并没有报告退出代码:

["a ^ 2"]
0          # !! BROKEN
Run Code Online (Sandbox Code Playgroud)

如果我用 withcmd /c call .\test.cmd调用,退出代码是正确的,但^字符会加倍:

PS> cmd /c call .\test.cmd "a ^ 2"; $LASTEXITCODE
["a ^^ 2"]  # !! BROKEN
1           # OK
Run Code Online (Sandbox Code Playgroud)

bea*_*ker 5

我不知道为什么会这样,但它确实有效:

cmd /c '.\test.cmd "a ^ 2" & exit'
$LASTEXITCODE
Run Code Online (Sandbox Code Playgroud)

输出:

["a ^ 2"] 
1
Run Code Online (Sandbox Code Playgroud)