PowerShell (Core) 的 7.3.0 版本引入了一个重大改变关于如何带有嵌入 " 字符的参数被传递给外部程序,比如winscp:
虽然这种变化是大多有益的,因为它修复了自 v1 以来根本被破坏的行为(this answer 讨论旧的、损坏的行为),它还总是打破现有的解决方法建立在破碎的行为之上,除了那些打电话给批处理文件以及 WSH CLI(wscript.exe 和 cscript.exe)及其关联的脚本文件(文件扩展名为 .vbs 和 .js)。
警告:
-
GitHub issue #18694 暗示7.3.1及以上版本 将做出这个突破性的改变选择参加, 但仅在 Windows 上, 为了向后兼容;那是:
- 在 Windows 上:
- 旧的解决方法将继续有效默认.
- 获得新的、正确的行为需要(暂时)设置
$PSNativeCommandArgumentPassing = 'Standard'
- 开启Unix- 类似平台:
- 新的正确行为 (
$PSNativeCommandArgumentPassing = 'Standard') 将保持默认
- 旧的解决方法需要(暂时)设置
$PSNativeCommandArgumentPassing = 'Legacy'才能继续工作,7.3.0 中已经如此
要使现有的解决方法继续有效,请将 $PSNativeCommandArgumentPassing preference variable(暂时)设置为 'Legacy':
# Note: Enclosing the call in & { ... } makes it execute in a *child scope*
# limiting the change to $PSNativeCommandArgumentPassing to that scope.
& {
$PSNativeCommandArgumentPassing = 'Legacy'
& winscp `
/log `
/command `
'echo Connecting...' `
"open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey=`"`"ssh-ed25519 includes spaces`"`""
}
不幸的是,因为winscp.exe只接受
"open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey=""ssh-ed25519 includes spaces""" 在它的进程命令行上(即嵌入的" 转义为""),而且也不是最广泛使用的形式
"open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey="ssh-ed25519 includes spaces""(嵌入"转义为"),固定行为现在采用,对于winscp.exe,具体而言,将继续需要解决方法.
如果你别想靠必须修改$PSNativeCommandArgumentPassing对于解决方法,这里是在其中起作用的解决方法两个都v7.2- 和 v7.3+:
-
利用--%,stop-parsing token,然而,它伴随着陷阱和严重的限制,特别是无法(直接)使用 PowerShell变量或它后面的参数中的子表达式 - 有关详细信息,请参阅this answer:
# Note: Must be single-line; note the --% and the
# unescaped use of "" in the argument that follows it.
# Only "..." quoting must be used after --%
# and the only variables that can be used are cmd-style
# *environment variables* such as %OS%.
winscp /log /command 'echo Connecting...' --% "open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey=""ssh-ed25519 includes spaces"""
-
最好通过cmd /c致电:
# Note: Pass-through command must be single-line,
# Only "..." quoting supported,
# and the embedded command must obey cmd.exe's syntax rules.
cmd /c @"
winscp /log /command "echo Connecting..." "open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey=""ssh-ed25519 includes spaces"""
"@
- 注意:您并非严格需要使用 here-string(
@"<newline>...<newline>"@ 或 @'<newline>...<newline>'@),但它有助于提高可读性并简化使用嵌入式引号的过程。
两种解决方法都允许您传递参数直接引用,但不幸的是还需要制定整个(传递)命令在一条线上.
背景资料:
Windows 上的 v7.3 默认值 $PSNativeCommandArgumentPassing,'Windows':
为一个突破性 v7.3 变化的影响总结,请参阅this comment on GitHub。
如果你有/需要编写跨版本、跨版本的PowerShell代码:Native module(Install-Module Native;由我撰写),有一个iefunction(简称:Invoke Executable),是一个 polyfill,它在绝大多数案例 - 只需将 ie 添加到您的外部程序调用中。
警告: 在手头的具体情况下,它会不是工作,因为它不知道 winscp.exe 需要 ""-转义。