相关文章推荐
千杯不醉的仙人球  ·  # yyds干货盘点 # ...·  11 月前    · 
微醺的荔枝  ·  OpenCV ...·  1 年前    · 
Write-Host book

PowerShell 将命令分解为两个标记, Write-Hostbook,并使用两种主要分析模式之一独立解释每个标记:表达式模式和参数模式。

当 PowerShell 分析命令输入时,它会尝试将命令名称解析为 cmdlet 或本机可执行文件。 如果命令名称没有完全匹配,PowerShell 会将 Get- 命令作为默认谓词追加到该命令前面。 例如,PowerShell 分析 ServiceGet-Service。 出于以下原因,不建议使用此功能:

  • 效率低下。 这会导致 PowerShell 多次搜索。
  • 将首先解析同名的外部程序,因此可能不会执行预期的 cmdlet。
  • Get-HelpGet-Command 无法识别无动词名称。
  • 命令名称可以是保留字或语言关键字。 Process 同时为 ,且 无法解析为 Get-Process
  • 表达式模式

    表达式模式用于合并表达式,这些表达式是脚本语言中的值操作所必需的。 表达式是 PowerShell 语法中值的表示形式,可以是简单或复合的,例如:

    文本表达式是其值的直接表示形式:

    'hello'
    

    变量表达式携带它们引用的变量的值:

    $script:path

    运算符结合其他表达式进行求值:

    -not $Quiet 3 + 7 $input.Length -gt 1
  • 字符串文本 必须包含在引号中。
  • 除非) 转义,否则数字被视为数值而不是 (一系列字符。
  • 运算符(包括 和 -not-一元运算符)和二元运算符(如 +-gt)被解释为运算符,并对其参数应用各自的运算 (操作数) 。
  • 属性和转换表达式 分析为表达式,并应用于从属表达式。 例如:[int] '7'
  • 变量引用 的计算结果为它们的值,但禁止 展开 ,并导致分析器错误。
  • 任何其他内容都被视为要调用的命令。
  • 分析时,PowerShell 首先将输入解释为表达式。 但是,当遇到命令调用时,分析将继续在参数模式下进行。 如果参数包含空格(如路径),则必须将这些参数值括在引号中。

    参数模式旨在分析 shell 环境中的命令的参数和参数。 所有输入都被视为可展开的字符串,除非它使用以下语法之一:

  • 美元符号 ($) 后跟变量名称开始变量引用,否则将其解释为可展开字符串的一部分。 变量引用可以包括成员访问或索引。

  • 简单变量引用后面的其他字符(如 $HOME)被视为同一参数的一部分。 将变量名称括在大括号 ({}) 中,以将其与后续字符分隔开。 例如,${HOME}
  • 当变量引用包含成员访问时,任何其他字符中的第一个将被视为新参数的开头。 例如 $HOME.Length-more ,生成两个参数:的值 $HOME.Length 和字符串文本 -more
  • 引号 ('") 开始字符串

  • 大括号 ({}) 开始新的脚本块

  • 逗号 (,) 引入作为数组传递的列表,除非调用的命令是本机应用程序,在这种情况下,它们被解释为可展开字符串的一部分。 不支持初始、连续或尾随逗号。

  • 括号 (()) 开始新表达式

  • 子表达式运算符 ($()) 开始嵌入表达式

  • 初始 at 符号 (@) 开始表达式语法,例如展开 () @args 、数组 (@(1,2,3)) 以及哈希表文本 (@{a=1;b=2}) 。

  • ()$()@() 在令牌的开头创建可包含表达式或嵌套命令的新分析上下文。

  • 当后跟其他字符时,第一个附加字符被视为新的单独参数的开头。
  • 当前面是无引号文本$()时,其工作方式类似于可展开的字符串,()启动一个表达式的新参数,并通过@()启动作为表达式的新参数作为文本@()
  • 其他所有内容都被视为可展开的字符串,但仍然需要转义的元字符除外。 请参阅 处理特殊字符

  • 参数模式元字符 (具有特殊语法含义的字符) 为: <space> ' " ` , ; ( ) { } | & < > @ #。 其中, < > @ # 仅在令牌开头具有特殊性。
  • 停止分析标记 (--%) 更改所有剩余参数的解释。 有关详细信息,请参阅下面的 停止分析令牌 部分。

    下表提供了在表达式模式和参数模式下处理的标记的几个示例,以及这些标记的计算。 对于这些示例,变量$a4的值为 。

    处理特殊字符

    反引号字符 (`) 可用于转义表达式中的任何特殊字符。 这对于转义要用作文本字符而不是元字符的参数模式元字符最为有用。 例如,若要使用美元符号 ($) 作为可展开字符串中的文本:

    "The value of `$ErrorActionPreference is '$ErrorActionPreference'."
    
    The value of $ErrorActionPreference is 'Continue'.
    

    还可以在行的末尾使用反引号字符,以便继续下一行的输入。 这提高了命令的可读性,该命令采用具有长名称和参数值的多个参数。 例如:

    New-AzVm `
        -ResourceGroupName "myResourceGroupVM" `
        -Name "myVM" `
        -Location "EastUS" `
        -VirtualNetworkName "myVnet" `
        -SubnetName "mySubnet" `
        -SecurityGroupName "myNetworkSecurityGroup" `
        -PublicIpAddressName "myPublicIpAddress" `
        -Credential $cred
    

    但是,应避免使用行延续。

  • 反引号字符可能很难看到,也很容易忘记。
  • 反引号中断行延续后的额外空格。 由于空间很难看到,因此可能很难找到错误。
  • PowerShell 提供了多种在语法中自然点换行的方法。

  • 管道字符 (|)
  • 在二元运算符 (+--eq等之后)
  • 在逗号后面 (, 数组中的)
  • 打开 、、 {[字符后(
  • 对于大型参数集,请改用 splatting。 例如:

    $parameters = @{
        ResourceGroupName = "myResourceGroupVM"
        Name = "myVM"
        Location = "EastUS"
        VirtualNetworkName = "myVnet"
        SubnetName = "mySubnet"
        SecurityGroupName = "myNetworkSecurityGroup"
        PublicIpAddressName = "myPublicIpAddress"
        Credential = $cred
    New-AzVm @parameters
    

    将自变量传递到本机命令

    从 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> 引用已定义的环境变量,则令牌将按原样传递。

    不能像) 一样 >file.txt 使用流重定向 (,因为它们作为参数逐字传递给目标命令。

    在以下示例中,第一步在不使用停止分析令牌的情况下运行命令。 PowerShell 计算带引号的字符串,并将值 (不带引号) 传递给 cmd.exe,这会导致错误。

    PS> cmd /c echo "a|b"
    'b' is not recognized as an internal or external command,
    operable program or batch file.
    PS> cmd /c --% echo "a|b"
    "a|b"
    

    Windows 系统上的某些命令作为 Windows 批处理文件实现。 例如,Azure CLI 的 az 命令是 Windows 批处理文件。

    传递包含引号字符的参数

    某些本机命令需要包含引号字符的参数。 PowerShell 7.3 更改了本机命令的命令行分析方式。

    新行为是 Window PowerShell 5.1 行为的 中断性变更 。 在调用本机应用程序时,这可能会中断用于解决各种问题的脚本和自动化。 使用停止分析令牌 (--%) 或 Start-Process cmdlet,以避免本机参数在需要时传递。

    新的 $PSNativeCommandArgumentPassing 首选项变量控制此行为。 此变量允许你在运行时选择行为。 有效值是 LegacyStandardWindows。 默认行为特定于平台。 在 Windows 平台上,默认设置为 Windows ,非 Windows 平台默认为 Standard

    Legacy 是历史行为。 和 Standard 模式的行为Windows相同,Windows但在 模式下,以下文件的调用会自动使用Legacy样式参数传递。

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • .bat 结尾
  • .cmd 结尾
  • .js 结尾
  • .vbs 结尾
  • .wsf 结尾
  • $PSNativeCommandArgumentPassing如果 设置为 LegacyStandard,则分析程序不会检查这些文件。

    以下示例使用 TestExe.exe 工具。 可以从源代码生成 TestExe 。 请参阅 PowerShell 源存储库中的 TestExe

    此更改提供的新行为:

  • 现在会保留带有嵌入引号的文本或可扩展字符串:

    PS> $a = 'a" "b'
    PS> TestExe -echoargs $a 'c" "d' e" "f
    Arg 0 is <a" "b>
    Arg 1 is <c" "d>
    Arg 2 is <e f>
    
  • 现在会保留作为参数的空字符串:

    PS> TestExe -echoargs '' a b ''
    Arg 0 is <>
    Arg 1 is <a>
    Arg 2 is <b>
    Arg 3 is <>
    

    这些示例的目的是将目录路径 (与空格和引号) "C:\Program Files (x86)\Microsoft\" 传递到本机命令,以便它接收带引号的字符串形式的路径。

    WindowsStandard 模式下,以下示例生成预期结果:

    TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
    TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'
    

    若要在 Legacy 模式下获得相同的结果,必须转义引号或使用停止分析标记 (--%) :

    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 --% """%ProgramFiles(x86)%\Microsoft\\""
    

    PowerShell 无法将反斜杠 (\) 字符识别为转义字符。 它是 ProcessStartInfo.ArgumentList 的基础 API 使用的转义字符。

    PowerShell 7.3 还添加了跟踪本机命令的参数绑定的功能。 有关详细信息,请参阅 Trace-Command

    将参数传递给 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>
    
  • about_Command_Syntax
  •