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 作用域修饰符:

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

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

变量值的序列化

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

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

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

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

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

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

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

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

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

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

另请参阅