about_Splatting

简短说明

介绍如何使用展开将参数传递给 PowerShell 中的命令。

长说明

Splatting 是一种将参数值集合作为一个单元传递给命令的方法。 PowerShell 将集合中的每个值与命令参数相关联。 展开的参数值存储在命名的 splatting 变量中,这些变量看起来像标准变量,但以 At 符号开头, @ () 而不是美元符号 ($) 。 At 符号告知 PowerShell 你传递的是值集合,而不是单个值。

展开使命令更短且更易于阅读。 可以在不同的命令调用中重复使用展开值,并使用 splatting 将参数值从 $PSBoundParameters 自动变量传递到其他脚本和函数。

从 Windows PowerShell 3.0 开始,还可以使用 splatting 来表示命令的所有参数。

语法

<CommandName> <optional parameters> @<HashTable> <optional parameters>
<CommandName> <optional parameters> @<Array> <optional parameters>

若要为不需要参数名称的位置参数提供参数值,请使用数组语法。 若要提供参数名称和值对,请使用哈希表语法。 已展开的值可以出现在参数列表中的任意位置。

展开时,无需使用哈希表或数组来传递所有参数。 可以使用 splatting 传递某些参数,并按位置或参数名称传递其他参数。 此外,还可以在单个命令中展开多个对象,这样就不会为每个参数传递多个值。

从 PowerShell 7.1 开始,可以通过在命令中显式定义参数来替代已展开的参数。

使用哈希表进行展开

使用哈希表来展开参数名称和值对。 可以将此格式用于所有参数类型,包括位置参数和开关参数。 位置参数必须按名称分配。

以下示例比较了将 Test.txt 文件复制到同一目录中的 Test2.txt 文件的两 Copy-Item 个命令。

第一个示例使用包含参数名称的传统格式。

Copy-Item -Path "test.txt" -Destination "test2.txt" -WhatIf

第二个示例使用哈希表展开。 第一个命令创建参数名称对和参数值对的哈希表,并将其存储在 变量中 $HashArguments 。 第二个命令在 $HashArguments 具有 splatting 的命令中使用 变量。 At 符号 (@HashArguments) 替换命令中的美元符号 ($HashArguments) 。

若要为 WhatIf 开关参数提供值,请使用 $True$False

$HashArguments = @{
  Path = "test.txt"
  Destination = "test2.txt"
  WhatIf = $true
}
Copy-Item @HashArguments

注意

在第一个命令中,At 符号 (@) 指示哈希表,而不是展开的值。 PowerShell 中哈希表的语法为: @{<name>=<value>; <name>=<value>; ...}

使用数组进行展开

使用数组为不需要参数名称的位置参数扩展值。 值必须按数组中的位置编号顺序排列。

以下示例比较了将 Test.txt 文件复制到同一目录中的 Test2.txt 文件的两 Copy-Item 个命令。

第一个示例使用省略参数名称的传统格式。 参数值在命令中按位置顺序显示。

Copy-Item "test.txt" "test2.txt" -WhatIf

第二个示例使用数组展开。 第一个命令创建参数值的数组,并将其存储在 变量中 $ArrayArguments 。 这些值在数组中按位置顺序排列。 第二个命令在 $ArrayArguments splatting 命令中使用 变量。 At 符号 (@ArrayArguments) 替换命令中的美元符号 ($ArrayArguments) 。

$ArrayArguments = "test.txt", "test2.txt"
Copy-Item @ArrayArguments -WhatIf

使用 ArgumentList 参数

多个 cmdlet 具有 ArgumentList 参数,用于将参数值传递给 cmdlet 执行的脚本块。 ArgumentList 参数采用传递给脚本块的值数组。 PowerShell 有效地使用数组展开将值绑定到脚本块的参数。 使用 ArgumentList 时,如果需要将数组作为绑定到单个参数的单个对象传递,则必须将该数组包装为另一个数组的唯一元素。

以下示例具有一个脚本块,该脚本块采用单个参数,该参数是字符串数组。

$array = 'Hello', 'World!'
Invoke-Command -ScriptBlock {
  param([string[]]$words) $words -join ' '
  } -ArgumentList $array

在此示例中,仅将 中的 $array 第一项传递给脚本块。

Hello
$array = 'Hello', 'World!'
Invoke-Command -ScriptBlock {
  param([string[]]$words) $words -join ' '
} -ArgumentList (,$array)

在此示例中, $array 包装在数组中,以便整个数组作为单个对象传递到脚本块。

Hello World!

示例

示例 1:在不同的命令中重复使用已展开的参数

此示例演示如何在不同的命令中重复使用已展开的值。 此示例中的命令使用 Write-Host cmdlet 将消息写入主机程序控制台。 它使用展开来指定前景色和背景色。

若要更改所有命令的颜色,只需更改 变量的值 $Colors

第一个命令创建参数名称和值的哈希表,并将哈希表存储在 变量中 $Colors

$Colors = @{ForegroundColor = "black"; BackgroundColor = "white"}

第二个和第三个命令使用 $Colors 变量在命令中 Write-Host 展开。 若要使用 $Colors variable,请将) ($Colors 美元符号替换为 At 符号 (@Colors) 。

#Write a message with the colors in $Colors
Write-Host "This is a test." @Colors

#Write second message with same colors. The position of splatted
#hash table does not matter.
Write-Host @Colors "This is another test."

示例 2:使用 $PSBoundParameters 转发参数

此示例演示如何使用 splatting 和 $PSBoundParameters 自动变量将其参数转发到其他命令。

自动 $PSBoundParameters 变量是一个字典对象 (System.Collections.Generic.Dictionary) ,其中包含运行脚本或函数时使用的所有参数名称和值。

在下面的示例中,我们使用 $PSBoundParameters 变量将传递给脚本或函数的参数值从 Test2 函数转发到 Test1 函数。 对 函数的Test1Test2两个调用都使用 splatting。

function Test1
{
    param($a, $b, $c)

    "a = $a"
    "b = $b"
    "c = $c"
}

function Test2
{
    param($a, $b, $c)

    #Call the Test1 function with $a, $b, and $c.
    Test1 @PSBoundParameters

    #Call the Test1 function with $b and $c, but not with $a
    Test1 -b $PSBoundParameters.b -c $PSBoundParameters.c
}

Test2 -a 1 -b 2 -c 3
a = 1
b = 2
c = 3
a =
b = 2
c = 3

示例 3:使用显式定义的参数替代已展开的参数

此示例演示如何使用显式定义的参数替代已展开的参数。 当你不想生成新的哈希表或更改用于 splat 的哈希表中的值时,这非常有用。

变量 $commonParams 存储用于在 East US 位置创建虚拟机的参数。 变量 $allVms 是要创建的虚拟机的列表。 我们将循环访问该列表,并使用 $commonParams 来展开参数来创建每个虚拟机。 但是,我们希望 myVM2 在与其他虚拟机不同的区域中创建。 可以显式在 $commonParamsNew-AzVm定义 Location 参数以取代 中$commonParams键的值Location,而不是调整哈希表。

$commonParams = @{
    ResourceGroupName = "myResourceGroup"
    Location = "East US"
    VirtualNetworkName = "myVnet"
    SubnetName = "mySubnet"
    SecurityGroupName = "myNetworkSecurityGroup"
    PublicIpAddressName = "myPublicIpAddress"
}

$allVms = @('myVM1','myVM2','myVM3',)

foreach ($vm in $allVms)
{
    if ($vm -eq 'myVM2')
    {
        New-AzVm @commonParams -Name $vm -Location "West US"
    }
    else
    {
        New-AzVm @commonParams -Name $vm
    }
}

示例 4:在单个命令中使用多个展开的对象

可以在单个命令中使用多个展开的对象。 在此示例中,不同的参数在单独的哈希表中定义。 哈希表在单个 Write-Host 命令中展开。

$a = @{
    Message         = 'Hello', 'World!'
}
$b = @{
    Separator       = '|'
}
$c = @{
    BackgroundColor = 'Cyan'
    ForegroundColor = 'Black'
}
Write-Host @a @b @c

Splatting 命令参数

可以使用 splatting 来表示命令的参数。 创建代理函数(即调用另一个命令的函数)时,此方法非常有用。 此功能在 Windows PowerShell 3.0 中引入。

若要展开命令的参数,请使用 @Args 表示命令参数。 此方法比枚举命令参数更容易,即使调用的命令的参数发生更改,此方法也无需修订。

该功能使用 $Args 自动变量,其中包含所有未分配的参数值。

例如,以下函数调用 Get-Process cmdlet。 在此函数中, @Args 表示 cmdlet 的所有参数 Get-Process

function Get-MyProcess { Get-Process @Args }

使用 Get-MyProcess 函数时,所有未分配的参数和参数值都传递给 @Args,如以下命令所示。

Get-MyProcess -Name PowerShell
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    463      46   225484     237196   719    15.86   3228 powershell
Get-MyProcess -Name PowerShell_Ise -FileVersionInfo
ProductVersion   FileVersion      FileName
--------------   -----------      --------
6.2.9200.16384   6.2.9200.1638... C:\Windows\system32\WindowsPowerShell\...

可以在 @Args 具有显式声明参数的函数中使用 。 可以在函数中多次使用它,但输入的所有参数都会传递给 的所有实例 @Args,如以下示例所示。

function Get-MyCommand
{
    Param ([switch]$P, [switch]$C)
    if ($P) { Get-Process @Args }
    if ($C) { Get-Command @Args }
}

Get-MyCommand -P -C -Name PowerShell
 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     50   112.76      78.52      16.64    6880   1 powershell

Path               : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Extension          : .exe
Definition         : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Source             : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Version            : 10.0.22621.3085
Visibility         : Public
OutputType         : {System.String}
Name               : powershell.exe
CommandType        : Application
ModuleName         :
Module             :
RemotingCapability : PowerShell
Parameters         :
ParameterSets      :
HelpUri            :
FileVersionInfo    : File:             C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
                     InternalName:     POWERSHELL
                     OriginalFilename: PowerShell.EXE.MUI
                     FileVersion:      10.0.22621.1 (WinBuild.160101.0800)
                     FileDescription:  Windows PowerShell
                     Product:          Microsoft&reg; Windows&reg; Operating System
                     ProductVersion:   10.0.22621.1
                     Debug:            False
                     Patched:          False
                     PreRelease:       False
                     PrivateBuild:     False
                     SpecialBuild:     False
                     Language:         English (United States)

备注

如果使用 CmdletBindingParameter 属性将函数转换为高级函数,则 $args 自动变量在函数中不再可用。 高级函数需要显式参数定义。

PowerShell Desired State Configuration (DSC) 不是设计为使用展开的。 不能使用展开将值传递到 DSC 资源。 有关详细信息,请参阅 Gael Colas 文章 伪展开 DSC 资源

另请参阅