通过 Invoke-Expression 传递 cmd 行 IF 语句会中断输出

Passing a cmd-line IF statement through Invoke-Expression breaks on output

如果我通过 PowerShell 的 Invoke-Expression 传递 IF 语句,该命令似乎正在 运行 正在完成,但随后似乎正在将输出作为新命令进行评估,而不是返回到 PowerShell。三个例子:

  1. Invoke-Expression 'echo "hi"'(无 IF 语句)

正常输出:hi

  1. Invoke-Expression 'cmd /c IF exist C:\Windows (echo "hi")'

输出错误:'hi' is not recognized as an internal or external command, operable program or batch file.

  1. Invoke-Expression 'cmd /c IF exist C:\Windows (query user)'

输出错误:

'" USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME"' is not recognized as an internal or external command, operable program or batch file.

从 PowerShell 运行 命令行 IF 语句并能够读取其输出的最佳方法是什么? 我试过 Start-Process 但不能为我的生活弄清楚如何阅读它的输出。尝试了从另一个 Whosebug post 复制的 System.Diagnostics.ProcessStartInfo 对象,但也没有成功。

因为人们一定会问:我首先通过 cmd 传递它的原因是因为整个代码块需要通过 Invoke-Command 传递到远程机器并且 cmd 具有 folder/file 访问其网络上的计算机,而 PowerShell 则不能。

您眼前的问题与 Invoke-Expressionwhich should generally be avoided:

的使用无关
cmd /c IF exist C:\Windows (echo "hi")  # WRONG

由 PowerShell 首先解释,预先 (echo "hi")(Write-Output "hi") 相同,PowerShell 将其扩展(插入)到命令的输出, 内容为 hi.

的字符串

cmd exe 最终看到的 - 损坏的 - 命令行如下,它解释了错误消息:

cmd /c IF exist C:\Windows hi

有关 PowerShell 如何解析不带引号的命令行参数的概述,请参阅


有多种方法可以解决该问题,适用于不同的场景:

# Single-quoting - passed as-is.
cmd /c 'IF exist C:\Windows (echo "hi")'

# Double-quoting - PowerShell would still expand $-prefixed tokens up front.
cmd /c "IF exist C:\Windows (echo `"hi`")"

#`# The stop-parsing symbol, --%, prevents PowerShell from parsing subsequent arguments, 
# with the exception of cmd-style environment-variable references (%FOO%)
cmd /c --% IF exist C:\Windows (echo "hi")

现在,使用 Invoke-Expression 您必须添加 escape 这些引号,因为必须将它们指定为 string[= 的一部分46=],但是,正如评论中提到的,很少需要 Invoke-Expression,这里也不需要,我也不希望它对 "double hop" authentication problem 有帮助你在评论中描述.

要解决后者,请尝试 this answer,它使用显式传递的凭据在远程计算机上建立辅助驱动器映射。