使用命令行中的完整路径和参数运行 powershell 命令 [英] Running a powershell command using full path and arguments from command line

查看:55
本文介绍了使用命令行中的完整路径和参数运行 powershell 命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个位于 Program Files 文件夹中的脚本并接受参数:verboserestart从它的文件夹运行它可以完美地运行:

powershell ./-verbose:$True -restart

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

powershell &"C:Program FilesFolder -verbose:$True -restart"

以上命令不运行脚本;相反,它打开 PS 命令提示符,退出时,它会在记事本中打开脚本.
我还尝试将每个变量放在单独的引号中,但效果不佳.

我通过使用 progra~1 而不是 Program Files 找到了一种解决方法,但我想以正确的方式解决该问题.

我错过了什么?

解决方案

顺便说一句:问题的引用相关部分可以通过使用环境变量 $env:ProgramFiles 而不是脚本路径中的文字 "C:Program Files...",这会将命令简化为:
powershell "&$env:ProgramFilesFolderfile.ps1 -verbose:$True -restart"


确实,为了在 PowerShell 中执行由带有嵌入空格的文字路径引用的脚本,那些路径必须引用并且引用的路径必须传递给 &.

但是,当使用 PowerShell 的 CLI使用-File(-f)来执行脚本更简单,这使得& 不必要并简化了引用:

powershell -File "C:Program FilesFolderfile.ps1";-详细 -重启

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

仅在需要传递PowerShell代码片段和/或参数脚本时才使用-Command (-c)-file 参数必须像从 inside PowerShell 那样解释:

powershell -Command "&'C:Program FilesFolderfile.ps1' -Verbose:$true -Restart

注意:为了能够将数组作为脚本文件参数传递,特别需要-Command;请参阅此答案.

您的尝试的关键改进是:

  • & 被放置在 "..." 中,这可以防止 cmd.exe 解释它本身之前 PowerShell 看到它.

  • 脚本路径包含在嵌入式引号中('...'),以便 PowerShell 将路径视为引用.

注意:

  • -Command 用于清晰;在Windows PowerShell 中,它可以省略(就像您所做的那样),因为它是默认 参数;但是请注意,在 PowerShell Core 中,默认值现在是 -File.请参阅此答案,全面了解这两个 PowerShell CLI.

  • 您并不严格需要将所有内容作为 one "..." 字符串传递,但这样在概念上更清晰.

详情见下文.

另请注意(进程)退出代码的设置方式在-File-Command之间有所不同- 请参阅此答案.


至于你尝试了什么:

<块引用>

以上命令不运行脚本;相反,它打开 PS 命令提示符,退出时,它会在记事本中打开脚本.

这意味着您正在从 cmd.exe(从命令提示符或批处理文件)调用,其中 一个 &<未包含在 "..." 中的/code> 具有特殊含义:它是 命令排序 运算符.

也就是说,您的命令等效于以下 2 个命令,按顺序执行:

powershellC:Program FilesFolderfile.ps1 -verbose:$True -restart"

第一个命令打开一个交互式 PowerShell 会话.只有在您手动退出后,它才会执行第二条命令.

请注意,您的具体症状表明您只使用了 "C:Program FilesFolder<file.ps1>>>>> 作为第二个命令,而没有参数,这确实会将该脚本文件作为文档打开,以便编辑.

使用参数,整个双引号字符串被解释为文件名,你会得到通常的 ... 不被识别为内部或外部命令,可操作程序或批处理文件.

为了cmd.exe& through 传递给正在调用的命令,它必须被括起来在 "..." 中,或者在这样的字符串之外,转义为 ^&.

然而,即使解决一个问题还不够:

rem # !!还是不行Powershell ^&C:Program FilesFolderfile.ps1 -verbose:$True -restart"

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

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

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

&C:Program FilesFolderfile.ps1 -verbose:$True -restart

如您所见,包含空格的脚本文件路径缺少必要的引用.

您有几个选项可以在脚本路径周围提供必要的引用:


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

powershell -Command "&'C:Program FilesFolderfile.ps1' -Verbose:$true -Restart

只有一对外部 " 字符,您不必担心 cmd.exe 会在前面 无意中解释您的参数em>,在他们到达 PowerShell 之前.

可以在这种情况下也可以省略外部引用,但这使得未引用参数容易被cmd.exe(虽然在这种情况下很好),并注意 'cmd.exe 中没有特殊含义,所以 PowerShell 风格的 '...' 字符串被 cmd.exe 视为未加引号:

rem # 有效,但通常不如上面的健壮.powershell -Command ^&'C:Program FilesFolderfile.ps1' -Verbose:$true -Restart


如果您想确保带有嵌入 ' 字符的偶数路径.正常工作:

使用嵌入的引用,将"转义为"(原文如此):

powershell -Command "&C:Program FilesFolderfile.ps1"-详细:$true -重新启动"

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

您可以通过使用 "" (sic) 来解决此问题,但这会使 "" 实例之间的字符串受 空格归一化:即将一行中的多个空格折叠成一个.

Windows PowerShell 中,您可以通过使用 "^""(原文如此)来避免这种情况,但请注意,在 PowerShell Core 您将获得与 "" 相同的行为.

rem # Windows PowerShell 中最强大的形式.rem # 仍然受 PowerShell Core 中的空白规范化约束.powershell -Command "&"^""C:Program FilesFolderfile.ps1"^""-详细:$true -重新启动"

I have a script that sits in Program Files folder and accepts arguments: verbose and restart Running it from its folder works perfectly:

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

Trying to run it using full path is where I have issues:

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

Above command doesn't run the script; Instead it's opening the PS command prompt and when exiting it, it opens the script in notepad.
I also tried to put each variable in a separate quote but that didn't work as well.

I found a workaround by using progra~1 instead of Program Files but I'd like to solve the issue the proper way.

What am I missing?

解决方案

As an aside: The quoting-related part of the problem could have been avoided by using environment variable $env:ProgramFiles instead of literal "C:Program Files..." in the script path, which would have simplified the command to:
powershell "& $env:ProgramFilesFolderfile.ps1 -verbose:$True -restart"


Indeed, in order to execute scripts referenced by literal paths with embedded spaces in PowerShell, those paths must be quoted and the quoted path must be passed to & or .

However, when using PowerShell's CLI it is simpler to use -File (-f) to execute a script, which makes & unnecessary and simplifies quoting:

powershell -File "C:Program FilesFolderfile.ps1" -Verbose -Restart

When PowerShell is called from the outside, arguments that follow -File are taken literally (after removing syntactic "...", if present) - they are not interpreted the way they would be if you ran the command from inside PowerShell; e.g., when calling from outside PowerShell, powershell -File script.ps1 $env:USERNAME would pass string $env:USERNAME verbatim to script.ps1 rather than expanding it - if you need that, use -Command.

Use -Command (-c) only if you need to pass a snippet of PowerShell code and/or arguments script-file arguments must be interpreted as they would from inside PowerShell:

powershell -Command "& 'C:Program FilesFolderfile.ps1' -Verbose:$true -Restart"

Note: -Command is notably needed in order to be able to pass arrays as script-file arguments; see this answer.

The crucial improvements to your attempt are:

  • & is placed inside "...", which prevents cmd.exe from interpreting it itself, before PowerShell sees it.

  • The script path is enclosed in embedded quoting ('...'), so that PowerShell sees the path as quoted.

Note:

  • -Command is used for clarity; in Windows PowerShell, it can be omitted (as you did), because it is the default parameter; note, however, that in PowerShell Core the default is now -File. See this answer for a comprehensive overview of the two PowerShell CLIs.

  • You don't strictly need to pass everything as one "..." string, but it is conceptually clearer that way.

See below for details.

Also note that how the (process) exit code is set differs between -File and -Command - see this answer.


As for what you tried:

Above command doesn't run the script; Instead it's opening the PS command prompt and when exiting it, it opens the script in notepad.

This implies that you're calling from cmd.exe (from the Command Prompt or a batch file), where an & not enclosed in "..." has special meaning: it is the command-sequencing operator.

That is, your command is the equivalent of the following 2 commands, executed in sequence:

powershell
"C:Program FilesFolderfile.ps1 -verbose:$True -restart"

The 1st command opens an interactive PowerShell session. Only after you manually exit it does the 2nd command get executed.

Note that your specific symptom suggests that you used only "C:Program FilesFolder<file.ps1>", without arguments, as the 2nd command, which would indeed open that script file as a document, for editing.

With the arguments, the entire double-quoted string is interpreted as a filename, and you'll get the usual ... is not recognized as an internal or external command, operable program or batch file.

In order for cmd.exe to pass a & through to a command being invoked, it must either be enclosed in "...", or, outside of such a string, escaped as ^&.

However, even fixing that one problem isn't enough:

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

The other problem is that when you use the -Command CLI parameter, which is implied in your case, PowerShell uses the following logic to process the arguments:

  • Each argument is stripped of its enclosing "...", if present.
  • The stripped arguments are concatenated with spaces.
  • The resulting single string is then executed as PowerShell code.

That is, with the above command PowerShell tried to execute a string with the following verbatim content:

& C:Program FilesFolderfile.ps1 -verbose:$True -restart

As you can see, the script file path, which contains a space, lacks the necessary quoting.

You have several options to provide the necessary quoting around the script path:


If you know that your script path does not contain ' chars, use embedded '...' quoting:

powershell -Command "& 'C:Program FilesFolderfile.ps1' -Verbose:$true -Restart"

With only a single, outer pair of " chars., you needn't worry about cmd.exe inadvertently interpreting your arguments up front, before they reach PowerShell.

You could also omit the outer quoting in this case, but that makes the unquoted arguments susceptible to unwanted interpretation by cmd.exe (though it's fine in this case), and note that ' has no special meaning in cmd.exe, so a PowerShell-style '...' string is considered unquoted by cmd.exe:

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


If you want to ensure that even paths with embedded ' chars. work properly:

Use embedded double-quoting, with the " escaped as " (sic):

powershell -Command "& "C:Program FilesFolderfile.ps1" -Verbose:$true -Restart"

Unfortunately, this again makes the string between the " instances subject to potentially unwanted interpretation by cmd.exe.

You can work around this by using "" (sic) instead, but that makes the string between the "" instances subject to whitespace normalization: that is, multiple spaces in a row are folded into one.

In Windows PowerShell, you can avoid that by using "^"" (sic), but note that in PowerShell Core you'll get the same behavior as with "".

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

这篇关于使用命令行中的完整路径和参数运行 powershell 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆