从命令行使用完整路径和参数运行powershell命令[重复]

yr9zkbsy  于 2023-11-18  发布在  Shell
关注(0)|答案(1)|浏览(165)

此问题在此处已有答案

How can I run a PowerShell script with white spaces in the path from the command line?(5个答案)
两年前关闭。
我有一个位于Program Files文件夹并接受参数的脚本:verboserestart从其文件夹运行它工作得很好:

powershell ./<file.ps1> -verbose:$True -restart

字符串
尝试使用完整路径运行它是我遇到问题的地方:

powershell & "C:\Program Files\Folder\<file.ps1> -verbose:$True -restart"


上面的命令不运行脚本;相反,它打开PS命令提示符,当退出它,它打开记事本中的脚本。
我也试着把每个变量放在一个单独的引号里,但效果不好。
我找到了一个解决方法,使用progra~1而不是Program Files,但我想以正确的方式解决这个问题。
我错过了什么?

u3r8eeie

u3r8eeie1#

顺便说一句:问题中与报价相关的部分可以通过在脚本路径中使用环境变量$env:ProgramFiles而不是文字"C:\Program Files\..."来避免,这将使命令简化为:
powershell "& $env:ProgramFiles\Folder\file.ps1 -verbose:$True -restart"
实际上,为了在PowerShell中执行由带有嵌入空格的文字路径引用的脚本,这些路径必须被 * 引用 *,并且引用的路径必须 * 传递给&. *
但是,当使用PowerShell's CLI时,使用-File-f)执行脚本
更简单,这使得&不必要并简化了引用:

powershell -File "C:\Program Files\Folder\file.ps1" -Verbose -Restart

字符串
当PowerShell被 * 从外部 * 调用时,**-File后面的参数被 * 逐字 *(在删除语法"..."之后,如果存在的话)-如果您从PowerShell内部运行命令,它们将不会被解释为它们的方式;例如,当从 * 外部 * PowerShell调用时,powershell -File script.ps1 $env:USERNAME会将字符串$env:USERNAME * 逐字 * 传递给script.ps1,而不是扩展它-如果需要,请使用-Command

仅当需要传递 * PowerShell代码片段 * 和/或参数时才使用-Command-c)脚本文件参数必须像在 * PowerShell内部一样解释:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"


注意:为了能够将 arrays 作为脚本文件参数传递,特别需要-Command;参见this answer
您的尝试的关键改进是:

  • &被放在"..."内部,这可以防止cmd.exe在PowerShell看到它之前解释它。
  • 脚本路径包含在 embedded 引号('...')中,以便PowerShell将路径视为引号。

注意事项:

  • -Command是为了清晰起见而使用的;在 Windows PowerShell 中,它可以被省略(就像你做的那样),因为它是 default 参数;但是,请注意,在PowerShell Core 中,默认值现在是-File。有关这两个PowerShell CLI的全面概述,请参阅this answer
  • 您并不严格需要将所有内容都作为 one"..."字符串传递,但这样在概念上更清晰。

详情见下文。
还请注意,-File-Command之间(进程)* 退出代码 * 的设置方式不同-参见this answer
至于你尝试了
上面的命令不运行脚本;相反,它打开PS命令提示符,当退出它,它打开记事本中的脚本。
这意味着您正在从cmd.exe(从命令提示符或批处理文件)调用,其中未包含在"..."中的&具有特殊含义:它是 * 命令排序 * 运算符。
也就是说,您的命令相当于以下 2 命令,按 * 顺序 * 执行:

powershell
"C:\Program Files\Folder\file.ps1 -verbose:$True -restart"


第一个命令打开一个 * 交互式 * PowerShell会话。只有在您手动退出它之后,第二个命令才会执行。
请注意,您的特定症状表明您只使用了"C:\Program Files\Folder\<file.ps1>",没有参数,作为第二个命令,这确实会将该脚本文件作为 document 打开,以进行 * 编辑 *。

  • 使用 * 参数,整个双引号字符串将被解释为文件名,您将得到通常的... is not recognized as an internal or external command, operable program or batch file.

为了让cmd.exe**将&through 传递给被调用的命令,它必须包含在"..."中,或者在这样的字符串之外,作为^&**进行转义。
然而,即使解决了这个 * 一个 * 问题是不够的:

rem # !! Still doesn't work
powershell ^& "C:\Program Files\Folder\file.ps1 -verbose:$True -restart"


另一个问题是,当您使用-Command CLI参数时,在您的情况下,PowerShell使用以下逻辑来处理参数:

  • 每个参数都被剥离其封闭的"..."(如果存在)。
  • 剥离的参数用空格连接。
  • 生成的单个字符串 * 然后 * 作为PowerShell代码执行。

也就是说,使用上述命令,PowerShell尝试执行具有以下逐字内容的字符串:

& C:\Program Files\Folder\file.ps1 -verbose:$True -restart


正如您所看到的,包含空格的脚本文件路径缺少必要的引号。
您有几个选项可以在脚本路径周围提供必要的引号:

如果您知道您的脚本路径 * 不 * 包含'字符,请使用 embedded'...'引号:

powershell -Command "& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart"


由于只有一个外部的"字符对,您不必担心cmd.exe在到达PowerShell之前无意中解释您的参数。
在这种情况下,您也可以 * 省略外部引号,但这会使 unquoted 参数容易受到cmd.exe不必要的解释(尽管在这种情况下没有问题),并注意'cmd.exe中没有特殊意义,因此cmd.exe将PowerShell样式的'...'字符串视为 unquoted

rem # Works, but generally less robust than the above.
powershell -Command ^& 'C:\Program Files\Folder\file.ps1' -Verbose:$true -Restart

如果您想确保即使路径中嵌入了'字符也能正常工作

使用嵌入式 * 双引号,将"转义为\"(原文如此):

powershell -Command "& \"C:\Program Files\Folder\file.ps1\" -Verbose:$true -Restart"


不幸的是,这再次使\"示例之间的字符串受到cmd.exe可能不必要的解释。

您可以通过使用\""(sic)来解决这个问题,但这会使\""示例之间的字符串受到 * 空白规范化 * 的影响:也就是说,一行中的多个空格被折叠成一个。
Windows PowerShell 中,您可以通过使用"^""(原文如此)来避免这种情况,但请注意,在PowerShell Core 中,您将获得与\""相同的行为,但在那里您可以使用"",它可以稳健地工作。

rem # The most robust form in Windows PowerShell.
rem # Still subject to whitespace normalization in PowerShell Core.
powershell -Command "& "^""C:\Program Files\Folder\file.ps1"^"" -Verbose:$true -Restart"

相关问题