powershell 在不退出的情况下从cmd命令打开pwsh

gab6jxml  于 2022-11-10  发布在  Shell
关注(0)|答案(3)|浏览(204)

我正在尝试启动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不能工作。
如有任何帮助,将不胜感激!谢谢!

eanckbw9

eanckbw91#

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

p8h8hvxi

p8h8hvxi2#

请参见pwsh documentation中的-Command参数。Cmd.exe不知道scriptBlock概念,并将{ssh test@test}解释为字符串。
当从cmd.exe触发pwsh.exe时,您应该这样做:

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

ldxq2e6h3#

注:

  • 以下答案适用于两个PowerShell版本的CLI,(powershell.exe适用于Windows PowerShell,pwsh适用于PowerShell (Core) 7+)
  • powershell -Command "& { ... }"/pwsh -Command "& { ... }"反模式,因此要避免
  • 使用"...",而不是"& { ... }",即直接指定所有命令,[1],避免不必要的语法仪式和不必要的处理(尽管后者在实践中无关紧要)。
  • 不幸的是,这种反模式非常常见,可能是因为旧版本的CLI文档错误地建议需要& { ... },但后来已更正了这一点。
    tl;dr
  • 从*PowerShell内部使用pwsh { ... }**(隐含-Command);在您的案例中:
pwsh.exe -noexit { ssh username@host }
  • 但是,请注意,很少需要从PowerShell内部调用PowerShell CLI(这涉及创建一个子进程)。在这里,您可以简单地直接调用ssh username@host
  • 从*PowerShell外部使用pwsh -Command " ... "**(或pwsh -c " ...");在您的情况下(如your own answer):
pwsh.exe -noexit "ssh username@host"

**外部*可以表示:

  • 来自另一个外壳,特别是cmd.exe
  • 从另一个外壳调用意味着必须首先满足its语法要求,这可能会因为"字符而变得棘手。转义为\"-请参见this answer以了解可靠的解决方法。
  • 无外壳上下文调用,例如Windows Run对话框(WinKey+R)和任务调度器启动的命令。
  • Windows上的所有(本地)外部上下文都需要引号("..."),但如果您从Unix*(POSIX兼容)外壳程序(如Bash)调用,引号也是一个选项。

有关PowerShell CLI的全面概述,请参阅this post

背景资料

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

  • 只有PowerShell内部才能与PowerShell CLI一起传递命令执行,因为PowerShell那里提供了{ ... }作为语法糖*:
  • 在幕后,脚本块中的代码是Base64编码的,并在最终通过-EncodedCommand构造的命令行上传递;类似地,传递给-Args的任何参数都是Base64编码的,并通过-EncodedArguments传递,并通过-OutputFormat XML请求CLIXML(PowerShell基于XML的进程间序列化格式)作为输出格式
  • 这与接收到的输出的自动反序列化相结合,确保尽可能保留PowerShell的丰富(基于.NET)类型系统和多个输出流的好处(涉及序列化时,类型保真度具有内在限制)。
  • 当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构造一个脚本块,由于它没有赋值给变量,因此默认情况下输出它,这意味着打印的脚本块的字符串表示*,这是脚本块的逐字内容,sans {}
  • 即,将逐字打印 Get-Date ,您也可以从PowerShell内部按如下方式进行验证:{ Get-Date }.ToString()

[1][1]从技术上讲,如果您想要将参数您的命令字符串内部传递到嵌入的脚本块,您可以使用"& { ... } ...",尽管在实践中很少需要这种级别的封装;一个特制的例子(从PowerShell外部调用):
pwsh -c "& { 'Time is now: ' + $args[0].TimeOfDay } (Get-Date)"

相关问题