【问题标题】:Open pwsh with command from cmd without exiting使用cmd命令打开pwsh而不退出
【发布时间】:2022-12-26 07:14:09
【问题描述】:

我正在尝试启动一个 Powershell 窗口,该窗口使用以下命令启动 ssh 会话:

pwsh.exe -noexit -Command {ssh <username>@<host>}

这在从 pwsh.exe 窗口本身执行时有效: 但是当从 cmd、运行窗口 (Win+R) 或任务计划程序(我需要它)执行时,它只显示应该执行的命令并启动 pwsh:

也就是不起作用的命令外部PowerShell 的是:

pwsh.exe -noexit -Command {ssh username@host}

这些命令当然已经在实际网站上进行了测试,其中 1 个有效而 2 个无效。
任何帮助将不胜感激!谢谢!

【问题讨论】:

    标签: powershell ssh cmd powershell-core


    【解决方案1】:

    笔记:

    • 下面的答案适用于 CLI两个都PowerShell 版本,(powershell.exe 用于 Windows PowerShell,pwsh 用于 PowerShell (Core) 7+

    • powershell -Command "& { ... }" / pwsh -Command "& { ... }" 是一个反模式, 因此避免:

      • 使用"...",而不是"& { ... }",即指定所有命令直接地,[1]这避免了不必要的语法仪式和不必要的处理(尽管后者在实践中无关紧要)。

      • 不幸的是,这种反模式很常见,可能是因为旧版本的 CLI 文档错误地建议 & { ... } 是必需的,但这已得到纠正。


    tl;博士

    • 里面电源外壳, 采用pwsh { ... }-Command暗示);在你的情况下:

      pwsh.exe -noexit { ssh username@host }
      
      • 但是请注意,很少需要从 PowerShell 内部调用 PowerShell CLI(这涉及创建一个子进程).在这里你可以简单地拨打ssh username@host直接地.
    • 外部电源外壳, 采用pwsh -Command " ... "(或pwsh -c " ..." );在你的情况下(如your own answer):

      pwsh.exe -noexit "ssh username@host"
      
      • 外部可以指:

        • 呼叫来自另一个外壳,特别是cmd.exe
          • 从另一个 shell 调用意味着它的必须首先满足语法要求,这对于 " 字符可能会变得棘手。被转义为 " - 请参阅 this answer 以获得可靠的解决方法。
        • 无壳上下文,例如 Windows Run 对话框(快捷键+R) 和任务计划程序启动的命令。
        • 所有(本地)外部上下文视窗要求双倍的-引用 ("..."),但如果您是从Unix(POSIX 兼容)shell,例如 Bash,单身的-引用也是一种选择。

    为一个PowerShell CLI 的全面概述,请参阅this post


    背景资料:

    { ... } 是 PowerShell script block 的字面形式,笼统地说是一段可重用的代码,必须按需调用,使用&(在子作用域中)或使用.(直接在调用者的作用域中):

    • 仅有的里面电源外壳它可以与 PowerShell CLI 一起使用来传递要执行的命令吗,因为那里的 PowerShell 提供了{ ... }作为语法糖:

      • 在幕后,脚本块内的代码经过Base64编码并通过命令行传递,最终通过-EncodedCommand构造;类似地,传递给-Args 的任何参数都经过 Base64 编码并通过-EncodedArguments 传递,并且通过-OutputFormat XML 请求 CLIXML(PowerShell 的基于 XML 的进程间序列化格式)作为输出格式
      • 这与自动反序列化收到的输出,确保尽可能多地保留 PowerShell 的丰富(基于.NET)类型系统和多个输出流的好处(当涉及序列化时,类型保真度具有固有的局限性- 参见this answer)。
    • 调用 PowerShell CLI 时来自外部(甚至通过细绳从 PowerShell 内部),语法糖确实不是申请,和脚本块文字(总是通过一个细绳争论)被解析为只是: 一段代码稍后打电话.

      • 因此,如果您尝试以下操作:

          # !! WRONG - simply *prints* what's between { and }
          # (Also applies if you don't use "..." from outside PowerShell.)
          pwsh -c "{ Get-Date }"
        
        • PowerShell 构造一个脚本块,并且由于它没有分配给变量,产出默认情况下,这意味着字符串表示的(否则未使用的)脚本块打印,这是逐字内容脚本块,没有 {}
        • 即逐字打印 Get-Date ,您也可以从 PowerShell 中按如下方式验证:{ Get-Date }.ToString()

    [1]技术上,如果你想通过,你可以使用"& { ... } ..."争论里面您的命令字符串到嵌入式脚本块,尽管在实践中很少需要这种级别的封装;一个人为的例子(从 PowerShell 外部调用):
    pwsh -c "& { 'Time is now: ' + $args[0].TimeOfDay } (Get-Date)"

    【讨论】:

      【解决方案2】:

      问题是我使用的花括号显然在 cmd 中不起作用,但在 pwsh 中起作用。要使命令在 CMD 中工作,只需使用双引号:
      pwsh.exe -noexit -Command "ssh username@host"

      【讨论】:

        【解决方案3】:

        查看pwsh documentation中的-Command参数。 cmd.exe 不知道脚本块概念并将 {ssh test@test} 解释为字符串。

        从 cmd.exe 触发 pwsh.exe 时,您应该执行如下操作:

        pwsh.exe -noexit -Command "& {ssh test@test}"
        

        【讨论】:

        • 谢谢!我已经弄明白了(见下面的答案),但是这里的“&”是什么?我们真的需要它吗?
        • @MySurmise:不,没有理由使用"& { ... }" 来调用通过-Command-c)参数传递给PowerShell CLI 的代码——只需直接使用"...",就像您在自己的回答中所做的那样。 CLI documentation 的旧版本错误地建议 & { ... } 是必需的,但这已得到纠正。
        • 此外,pwsh -Command 也可以使用脚本块调用(从 PowerShell 内部,使用脚本块暗示-Command),所以这与是否使用-Command无关,而是关于是否传递了真正的脚本块(仅可能来自 PowerShell 内部)或是否传递了一个细绳代表一个脚本块。当一个细绳被传递,嵌入其中的脚本块如此解析,但不是执行.换句话说:它是不是解释为字符串;它确实变成了一个脚本块,但是,在没有调用或保存它的情况下,它是输出, 就像它一样逐字内容.
        猜你喜欢
        • 1970-01-01
        • 2013-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-01
        • 1970-01-01
        • 2013-08-09
        • 1970-01-01
        相关资源
        最近更新 更多