我在一个PowerShell脚本中使用WinSCP。它突然停止工作。过了一段时间我可以弄清楚这个问题是从一个更新版本的PowerShell中出现的:
简化代码:
& winscp `
/log `
/command `
'echo Connecting...' `
"open sftp://kjhgk:jkgh@lkjhlk.com/ -hostkey=`"`"ssh-ed25519 includes spaces`"`""
使用v7.2.7的错误消息
您lkjhlk.com不存在!
使用v7.3.0的错误消息
命令“open”的参数太多。
正如你所看到的v7.3.0 WinSCP接收不同的输入取决于版本的PS.我发现,差异有一些做的空格在主机键.如果他们被省略v7.3.0输出相同的错误.
PowerShell的什么更改导致了这个问题,我该如何修复它?(我该如何调试这样的问题?我玩了一点转义,但字符串看起来都一样,无论版本如何,没有明显的破坏性更改可以负责)
1条答案
按热度按时间zzwlnbp81#
"
字符的参数 * 传递给 * 外部程序**,例如winscp
:虽然此更改 * 大部分 * 是有益的,因为它修复了自v1以来从根本上破坏的行为(this answer讨论旧的、破坏的行为),它**还 * 总是 * 破坏建立在破坏的行为上的现有变通办法***, 除了 * 调用 * 批处理文件 * 和WSH CLI(
wscript.exe
和cscript.exe
)及其关联脚本文件(文件扩展名为.vbs
和.js
)的命令。$PSNativeCommandArgumentPassing = 'Standard'
$PSNativeCommandArgumentPassing = 'Standard'
)将保留默认值$PSNativeCommandArgumentPassing = 'Legacy'
才能继续工作,7.3.0中已经是这种情况$PSNativeCommandArgumentPassing
首选项变量(临时)设置为'Legacy'
**:不幸的是因为
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 +中均起作用的变通方法:--%
,即停止解析标记**,但是它有缺陷和严重的限制,特别是不能(直接)在其后的参数中使用PowerShell * 变量 * 或子表达式-请参阅this answer了解详细信息;但是,如果您将--%
用作 * array * 的一部分,则可以绕过这些限制,首先构造 * array * 并将其赋给变量,然后通过splatting传递:cmd /c
呼叫:@"<newline>...<newline>"@
或@'<newline>...<newline>'@
),但它有助于提高可读性并简化嵌入式引号的使用。这两种变通方法都允许您 * 直接以带引号的形式 * 传递参数,但不幸的是,还需要在一行 * 上制定整个(传递)命令 *-除非
--%
与splitting组合使用。背景信息:
Windows上v7.3的默认
$PSNativeCommandArgumentPassing
值'Windows'
:wscript.exe
和cscript.exe
)及其关联的脚本文件(文件扩展名为.vbs
和.js
)。"
):CommandLineToArgv
WinAPI函数的解析规则的程序编码参数,这是解析进程命令行的 * 最广泛遵守的约定 *。"
字符***嵌入 * 在参数中,被目标程序视为它的 * 逐字部分 *,被转义为\"
,而\
本身 * 仅 * 在它位于"
之前但要被解释为 * 逐字 * 时才需要转义 *(作为\\
)。$PSNativeCommandArgumentPassing
值设置为'Standard'
(这是类Unix平台上的默认值,其中此模式修复 * 所有 * 问题,并使v7.3+代码永远不需要解决方案),则此行为适用于 * 所有 * 外部程序,即上述例外不再适用)。有关v7.3重大变更的影响总结,请参见GitHub上的此评论。
如果您需要编写跨版本的PowerShell代码:将
Native
module(Install-Module Native
;作者),具有**ie
**函数(缩写为:Invoke Executable)是一个polyfill,在 * 绝大多数 * 情况下,它提供了无变通方案的跨版本(v3+)、跨平台和跨版本行为-只需将ie
前置到外部程序调用中。警告:在当前的特定情况下,它将 * 不 * 工作,因为它不知道
winscp.exe
需要""
-转义。