简短说明
介绍 PowerShell 如何分析命令。
详细说明
在命令提示符处输入命令时,PowerShell 会将命令文本分解为 令牌 的一系列段,然后确定如何解释每个令牌。
例如,如果键入:
Write-Host book
PowerShell 将命令分解为两个令牌,Write-Host 和 book,并使用两种主要分析模式之一(表达式模式和参数模式)独立解释每个令牌。
注释
当 PowerShell 分析命令输入时,它会尝试将命令名称解析为 cmdlet 或本机可执行文件。 如果命令名称没有完全匹配,PowerShell 会将命令作为默认动词添加到 Get- 前面。 例如,PowerShell 将 Process 分析为 Get-Process。 出于以下原因,不建议使用此功能:
- 效率低下。 这会导致 PowerShell 多次搜索。
- 首先解析具有相同名称的外部程序,因此不能执行预期的 cmdlet。
- 
              Get-Help和Get-Command无法识别无谓词名称。
表达式模式
表达式模式用于组合表达式,这些表达式是脚本语言中值操作所必需的。 表达式是 PowerShell 语法中值的表示形式,可以是简单或复合值,例如:
文本表达式是其值的直接表示形式:
'hello'
32
变量表达式承载它们引用的变量的值:
$x
$script:path
运算符将其他表达式组合在一起来进行计算:
-12
-not $Quiet
3 + 7
$input.Length -gt 1
- 字符串文本 必须包含在引号中。
- 数字被视为数值而不是一系列字符(除非转义)。
- 
              运算符(包括一元运算符(如 -和-not)和二元运算符(如+和-gt)被解释为运算符,并对其参数(操作数)应用各自的运算。
- 
              属性和转换表达式 被解析为表达式并应用于从属表达式,例如 [int] '7'.
- 变量引用 将计算为其值,但禁止 展开 (即粘贴预填充的参数集),并会导致解析器错误。
- 其他任何内容都将被视为要调用的命令。
参数模式
分析时,PowerShell 首先将输入解释为表达式。 但是,当遇到命令调用时,分析将继续处于参数模式。 如果有包含空格(如路径)的参数,则必须将这些参数值括在引号中。
参数模式旨在解析 shell 环境中命令的参数和参数值。 所有输入都被视为可扩展字符串,除非它使用以下语法之一:
- 美元符号 () - $后跟变量名称开始变量引用,否则将解释为可扩展字符串的一部分。 变量引用可以包括成员访问或索引。- 遵循简单变量引用的其他字符(如 $HOME)被视为同一参数的一部分。 将变量名称括在大括号({})中,以将其与后续字符分开。 例如,${HOME}。
- 当变量引用包括成员访问时,任何其他字符中的第一个字符被视为新参数的开头。 例如,$HOME.Length-more产生两个参数:$HOME.Length的值和字符串文本-more。
 
- 遵循简单变量引用的其他字符(如 
- 引号( - '和- ")是字符串的开头
- 大括号 ( - {}) 是新脚本块的开头
- 逗号 () - ,引入以数组形式传递的列表,但要调用的命令是本机应用程序时除外,在这种情况下,它们将被解释为可扩展字符串的一部分。 不支持首字母、连续逗号或尾随逗号。
- 括号 ( - ()) 开始一个新表达式
- 子表达式运算符 ( - $()) 开始嵌入表达式
- 初始 - @符号是表达式语法的开头,例如展开 (- @args)、数组 (- @(1,2,3)) 和哈希表文本 (- @{a=1;b=2})。
- 在令牌开头 - ()、- $()和- @()创建一个新的分析上下文,该上下文可以包含表达式或嵌套命令。- 后跟其他字符时,第一个附加字符被视为新的单独参数的开头。
- 当前面有未加引号的文本时,其 $()工作方式类似于可扩展字符串,()启动一个作为表达式的新参数,并@()被视为作为文本@,并()启动一个作为表达式的新参数。
 
- 其他所有内容都被视为可扩展字符串,但仍然需要转义的元字符除外。 - 参数模式元字符(具有特殊语法含义的字符)是:<space> ' " ` , ; ( ) { } | & < > @ #。 其中,< > @ #仅在标记开头是特殊的。
 
- 参数模式元字符(具有特殊语法含义的字符)是:
- 停止分析标记( - --%)更改所有剩余参数的解释。 有关详细信息,请参阅下面的停止分析标记部分。
例子
下表提供了表达式模式和参数模式中处理的令牌的几个示例,以及这些令牌的计算。 对于这些示例,变量 $a 的值 4。
| 示例: | 模式 | 结果 | 
|---|---|---|
| 2 | 表达式 | 2 (整数) | 
|  `2 | 表达式 | “2”(命令) | 
| Write-Output 2 | 表达式 | 2 (整数) | 
| 2+2 | 表达式 | 4 (整数) | 
| Write-Output 2+2 | 论点 | “2+2”(字符串) | 
| Write-Output(2+2) | 表达式 | 4 (整数) | 
| $a | 表达式 | 4 (整数) | 
| Write-Output $a | 表达式 | 4 (整数) | 
| $a+2 | 表达式 | 6 (整数) | 
| Write-Output $a+2 | 论点 | “4+2”(字符串) | 
| $- | 论点 | "$-"(命令) | 
| Write-Output $- | 论点 | "$-"(字符串) | 
| a$a | 表达式 | "a$a"(命令) | 
| Write-Output a$a | 论点 | “a4”(字符串) | 
| a'$a' | 表达式 | "a$a"(命令) | 
| Write-Output a'$a' | 论点 | "a$a"(字符串) | 
| a"$a" | 表达式 | "a$a"(命令) | 
| Write-Output a"$a" | 论点 | “a4”(字符串) | 
| a$(2) | 表达式 | "a$(2)"(命令) | 
| Write-Output a$(2) | 论点 | “a2”(字符串) | 
每个标记都可以解释为某种对象类型,例如 布尔 或 字符串。 PowerShell 尝试从表达式中确定对象类型。 对象类型取决于命令所需的参数类型,以及 PowerShell 是否知道如何将参数转换为正确的类型。 下表显示了分配给表达式返回的值的类型的几个示例。
| 示例: | 模式 | 结果 | 
|---|---|---|
| Write-Output !1 | 参数 | "!1"(字符串) | 
| Write-Output (!1) | 表达式 | False(布尔值) | 
| Write-Output (2) | 表达式 | 2 (整数) | 
| Set-Variable AB A,B | 参数 | 'A','B'(数组) | 
| CMD /CECHO A,B | 参数 | “A,B”(字符串) | 
| CMD /CECHO $AB | 表达式 | 'A B'(数组) | 
| CMD /CECHO :$AB | 参数 | ':A B'(字符串) | 
将参数传递给本地命令
从 PowerShell 运行本机命令时,参数首先由 PowerShell 分析。 然后,分析的参数将联接到单个字符串中,每个参数用空格分隔。
例如,以下命令调用 icacls.exe 程序。
icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
若要在 PowerShell 2.0 中运行此命令,必须使用转义字符来防止 PowerShell 错误解释括号。
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
停止分析标记
从 PowerShell 3.0 开始,可以使用 停止分析(--%)令牌来阻止 PowerShell 将输入解释为 PowerShell 命令或表达式。
注释
停止解析令牌仅适用于 Windows 平台。
调用本机命令时,将停止分析令牌置于程序参数之前。 此方法比使用转义字符来防止误解要容易得多。
遇到停止分析令牌时,PowerShell 会将行中的剩余字符视为文本。 它执行的唯一解释是替换使用标准 Windows 表示法的环境变量的值,例如 %USERPROFILE%。
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
PowerShell 将以下命令字符串发送到 icacls.exe 程序:
X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
停止分析标记仅在下一个换行符或管道字符之前有效。 不能使用延续字符 ()` 来扩展其效果,也不能使用命令分隔符 (); 来终止其效果。
除了环境变量引用之外 %variable% ,您不能在命令中嵌入任何其他动态元素。 不支持将 % 字符转义为 %%,就像在批处理文件中执行的方式一样。 
              %<name>% 标记不断扩展。 如果不 <name> 引用定义的环境变量,则令牌将通过 as-is传递。
您不能使用流重定向(如 >file.txt),因为它们是作为参数逐字传递给 target 命令的。
传递包含引号字符的参数
某些本机命令需要包含引号字符的参数。 通常,PowerShell 的命令行分析会删除提供的引号字符。 然后,分析的参数将联接到单个字符串中,每个参数用空格分隔。 然后将此字符串分配给  对象的 Arguments 属性ProcessStartInfo。 字符串中的引号必须使用额外的引号或反斜杠 (\) 字符进行转义。
注释
PowerShell 不会将反斜杠 ()\ 字符识别为转义字符。 它是底层 API ProcessStartInfo.Arguments用于 的转义字符。
有关转义要求的详细信息,请参阅 ProcessStartInfo.Arguments 的文档。
以下是使用该工具 TestExe.exe 的示例。 PowerShell 源存储库中的 Pester 测试使用此工具。 这些示例的目标是将目录路径 "C:\Program Files (x86)\Microsoft\" 传递给本机命令,以便它以带引号的字符串形式接收路径。
              
               的 echoargs 参数显示作为可执行文件的参数接收的值TestExe。 可使用此工具验证是否已正确转义参数中的字符。
TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs """""C:\Program Files (x86)\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% "\"C:\Program Files (x86)\Microsoft\\"
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""
以下所有示例的输出相同:
Arg 0 is <"C:\Program Files (x86)\Microsoft\">
可以从源代码生成 TestExe。 请参阅 TestExe。
将参数传递给 PowerShell 命令
从 PowerShell 3.0 开始,可以使用 参数结束令牌(--)来阻止 PowerShell 将输入解释为 PowerShell 参数。 这是 POSIX Shell 和实用工具规范中指定的约定。
参数结束标记(--)表示,其后面的所有参数都将以实际形式传递,就像在它们周围放置了双引号一样。 例如,使用 -- 可以输出字符串 -InputObject,而无需使用引号或将其解释为参数:
Write-Output -- -InputObject
-InputObject
与停止分析(--%)令牌不同,-- 令牌后面的任何值都可以由 PowerShell 解释为表达式。
Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64
此行为仅适用于 PowerShell 命令。 如果在调用外部命令时使用 -- 令牌,-- 字符串将作为参数传递给该命令。
TestExe -echoargs -a -b -- -c
输出显示,-- 作为参数传递给 TestExe。
Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>