about_Remote_Variables

简短说明

说明如何在远程命令中使用本地和远程变量。

长说明

可以在远程计算机上运行的命令中使用变量。 为变量赋值,然后使用变量代替值。

默认情况下,假定远程命令中的变量在运行命令的会话中定义。 在本地会话中定义的变量必须标识为命令中的局部变量。

使用远程变量

PowerShell 假定远程命令中使用的变量在运行命令的会话中定义。

在此示例中,$ps 变量在运行 Get-WinEvent 命令的临时会话中定义。

Invoke-Command -ComputerName S1 -ScriptBlock {
  $ps = "*PowerShell*"; Get-WinEvent -LogName $ps
}

当命令在永久性会话中运行时,远程变量 PSSession 必须在该会话中定义。

$s = New-PSSession -ComputerName S1
Invoke-Command -Session $s -ScriptBlock {$ps = "*PowerShell*"}
Invoke-Command -Session $s -ScriptBlock {Get-WinEvent -LogName $ps}

使用局部变量

可以在远程命令中使用局部变量,但必须在本地会话中定义该变量。

从 PowerShell 3.0 起,可以使用 Using: 范围修饰符在远程命令中标识局部变量。

Using: 的语法如下所示:

$Using:<VariableName>

在以下示例中,$ps 变量是在本地会话中创建的,但在运行命令的会话中使用。 Using: 范围修饰符将 $ps 标识为局部变量。

$ps = "*PowerShell*"
Invoke-Command -ComputerName S1 -ScriptBlock {
  Get-WinEvent -LogName $Using:ps
}

Using: 作用域修饰符可用于 PSSession

$s = New-PSSession -ComputerName S1
$ps = "*PowerShell*"
Invoke-Command -Session $s -ScriptBlock {Get-WinEvent -LogName $Using:ps}

变量引用(如 $Using:var )从调用方上下文扩展到变量 $var 的值。 无法访问调用方变量对象。 Using: 范围修饰符不能用于修改 PSSession 中的局部变量。 例如,以下代码不适用:

$s = New-PSSession -ComputerName S1
$ps = "*PowerShell*"
Invoke-Command -Session $s -ScriptBlock {$Using:ps = 'Cannot assign new value'}

有关 Using: 的详细信息,请参阅 about_Scopes

使用分散参数传递

PowerShell Splatting 将参数名称和值的集合传递给命令。 有关详细信息,请参阅 about_Splatting

在此示例中,splatting 变量 $Splat 是在本地计算机上设置的哈希表。 Invoke-Command 连接到远程计算机会话。 ScriptBlock 使用具有 At (Using:) 符号的 @ 范围修饰符来表示已展开的变量。

$Splat = @{ Name = "Win*"; Include = "WinRM" }
Invoke-Command -Session $s -ScriptBlock { Get-Service @Using:Splat }

需要 Using: 范围修饰符的其他情况

对于任何在会话外执行的脚本或命令,需要使用 Using: 作用域修饰符来嵌入来自调用会话作用域的变量值,以便会话外代码可以访问它们。 以下上下文支持 Using: 作用域修饰符:

  • 远程执行的命令,开头的 Invoke-Command 使用 ComputerNameHostNameSSHConnection会话参数(远程会话)
  • 后台作业,从 Start-Job 开始(进程外会话)
  • 线程作业,以 Start-ThreadJobForEach-Object -Parallel 开始(单独的线程会话)

根据上下文,嵌入的变量值可以是调用方作用域数据的独立副本,也可以是对其的引用。 在远程和进程外会话中,这些变量值始终是独立的副本。 在线程会话中,它们通过引用传递。

变量值的序列化

远程执行的命令和后台作业在进程外运行。 进程外会话使用基于 XML 的序列化和反序列化,使变量值可以跨进程边界使用。 序列化进程将对象转换为 PSObject,其中包含原始对象属性,但不包含其方法。

对于一组有限类型,反序列化解除对象冻结,回到原始类型。 解除冻结的对象是原始对象实例的副本。 它具有类型属性和方法。 对于简单类型(如 System.Version),副本完全相同。 对于复杂类型,副本不完善。 例如,解除冻结的证书对象不包括私钥。

所有其他类型的实例都是 PSObject 实例。 pstypenames 属性包含前缀为 反序列化的原始类型名称,例如,Deserialized.System.Data.DataTable

将局部变量与 ArgumentList 参数配合使用

可以通过定义远程命令的参数并使用 cmdlet 的 Invoke-Command 参数将本地变量指定为参数值,从而在远程命令中使用局部变量。

  • 使用 param 关键字定义远程命令的参数。 参数名称是不需要与局部变量名称匹配的占位符。

  • 使用命令中由 param 关键字定义的参数。

  • 使用 cmdlet 的 Invoke-Command 参数将局部变量指定为参数值。

例如,以下命令在本地会话中定义 $ps 变量,然后在远程命令中使用它。 该命令使用 $Log 作为参数名称和局部变量 ($ps) 作为其值。

$ps = "*PowerShell*"
Invoke-Command -ComputerName S1 -ScriptBlock {
  param($Log)
  Get-WinEvent -LogName $Log
} -ArgumentList $ps

另请参阅