我在 Powershell 腳本中使用 WinSCP。它突然停止作業。一段時間后,我發現問題出現在較新版本的 PowerShell 中:
減少代碼:
& winscp `
/log `
/command `
'echo Connecting...' `
"open sftp://kjhgk:[email protected]/ -hostkey=`"`"ssh-ed25519 includes spaces`"`""
使用 v7.2.7 的錯誤資訊
主機 "lkjhlk.com" 不存在。
使用 v7.3.0 的錯誤訊息
命令“打開”的引數太多。
正如您在 v7.3.0 中看到的那樣,WinSCP 根據 PS 的版本接收不同的輸入。我發現差異與主機密鑰中的空格有關。如果省略它們,v7.3.0 會輸出相同的錯誤。
PowerShell 的哪些更改導致了此問題,我該如何解決?(我該如何除錯此類問題?我嘗試了一些轉義,但無論版本如何,字串看起來都一樣,沒有明顯的破壞性變化可能是負責任的)
uj5u.com熱心網友回復:
PowerShell (Core) 7.3 版在如何將帶有嵌入"字符的引數傳遞給外部程式方面引入了重大更改,例如winscp:
雖然此更改主要是有益的,因為它修復了自 v1 以來根本損壞的行為(此答案討論了舊的、損壞的行為),但它也總是會破壞基于損壞行為構建的現有解決方法,除了那些呼叫批處理檔案和WSH CLI(wscript.exe和cscript.exe)及其關聯的腳本檔案(具有檔案擴展名,例如.vbs和.js)。
要使現有的解決方法繼續作業,請將$PSNativeCommandArgumentPassing首選項變數(暫時)設定為'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:[email protected]/ -hostkey=`"`"ssh-ed25519 includes spaces`"`""
}
不幸的是,因為wincp.exe僅
"open sftp://kjhgk:[email protected]/ -hostkey=""ssh-ed25519 includes spaces"""在其行程命令列上接受(即,嵌入"轉義為""),而不是最廣泛使用的形式
"open sftp://kjhgk:[email protected]/ -hostkey=\"ssh-ed25519 includes spaces\""(嵌入"轉義為\"),固定行為現在采用,winscp.exe具體而言,將繼續需要解決方法.
如果您不想依賴修改$PSNativeCommandArgumentPassing來解決變通辦法,以下是在v7.2- 和 v7.3 中都有效的變通辦法:
使用stop-parsing token
--%,然而,它帶有陷阱和嚴重的限制,特別是無法(直接)在它后面的引數中使用 PowerShell變數或子運算式 - 有關詳細資訊,請參閱此答案:# 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 variable that can be used are cmd-style # *environment variables* such as %OS%. winscp /log /command 'echo Connecting...' --% "open sftp://kjhgk:[email protected]/ -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:[email protected]/ -hostkey=""ssh-ed25519 includes spaces""" "@- 注意:您并非嚴格需要使用此處字串(
@"<newline>...<newline>"@或@'<newline>...<newline>'@),但它有助于提高可讀性并簡化使用嵌入式引號的程序。
- 注意:您并非嚴格需要使用此處字串(
這兩種解決方法都允許您直接按參考傳遞引數,但不幸的是還需要在一行中制定整個(傳遞)命令。
背景資料:
$PSNativeCommandArgumentPassingWindows 上的 v7.3 默認值'Windows':
遺憾的是,保留了呼叫批處理檔案和 WSH CLI(
wscript.exe和cscript.exe)及其相關腳本檔案(具有檔案擴展名,如.vbs和.js)的舊的、損壞的行為。雖然僅對于這些程式,這允許現有的變通辦法繼續發揮作用,但僅需要在 v7.3 中運行的未來代碼將繼續因需要這些模糊的變通辦法而負擔重擔,這些變通辦法建立在損壞的行為之上。
- 未實施的替代方案是為這些程式構建住宿以及一些與程式無關的住宿到 PowerShell,因此在絕大多數情況下,將來甚至不需要變通辦法:請參閱GitHub 問題 #15143。
還有一些麻煩的跡象表明,這個例外串列將被逐個附加到,這幾乎保證了給定 PowerShell 版本的混淆,即哪些程式需要解決方法,哪些不需要。
值得稱贊的是,對于所有其他程式, PowerShell 在必要時對引數進行編碼,如下所示在幕后重建
"命令列:它為遵循C 命令列決議規則(由 C/C /.NET 應用程式使用)/
CommandLineToArgvWinAPI 函式的決議規則的程式的引數進行編碼,這是決議行程命令列的最廣泛遵守的約定.簡而言之,這意味著嵌入在引數中的嵌入
"字符,被目標程式視為它的 逐字部分,被轉義為,如果它在 a 之前但要被解釋,則它本身只需要轉義(as )逐字逐句。\"\\\"請注意,如果您將
$PSNativeCommandArgumentPassingvalue 設定為'Standard'(這是類 Unix 平臺上的默認值,此模式修復了所有問題并使 v7.3 代碼永遠不需要解決方法),此行為適用于所有外部程式,即上述例外不再申請)。
有關突破性 v7.3 更改影響的摘要,請參閱GitHub 上的此評論。
如果您有/需要撰寫跨版本、跨版本的 PowerShell 代碼:該Native模塊(Install-Module Native;由我撰寫)具有一個ie函式(簡稱:Invoke Executable),是一個提供無變通方法的跨版本(v3 )的 polyfill )、跨平臺和跨版本行為在絕大多數情況下 - 只需ie 添加到您的外部程式呼叫之前。
警告:在手頭的特定情況下它不會作業,因為它不知道winscp.exe需要""-escaping。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/535821.html
