Powershell PSSession变量上下文

Powershell PSSession变量上下文,powershell,Powershell,我使用newpssession通过Invoke命令在远程机器上运行命令。举个例子,假设我运行命令的机器名为FROM-machine,我运行命令的机器名为TO-machine $session = New-PSSession -ComputerName TO-MACHINE $script = ScriptBlock::Create("Write-Host Machine name is $env:COMPUTERNAME") Invoke-Command -session $session -s

我使用newpssession通过Invoke命令在远程机器上运行命令。举个例子,假设我运行命令的机器名为FROM-machine,我运行命令的机器名为TO-machine

$session = New-PSSession -ComputerName TO-MACHINE
$script = ScriptBlock::Create("Write-Host Machine name is $env:COMPUTERNAME")
Invoke-Command -session $session -scriptBlock $script
我预计这将产生:

Machine name is TO-MACHINE
然而,它实际上是输出的

Machine name is FROM-MACHINE
在文件路径的情况下也会发生这种情况-如果我想在“C:\myprogram.exe”处运行程序,powershell将尝试在“\\FROM-MACHINE\C$\myprogram.exe”处查找myprogram.exe


我的问题是:是否有任何方法(除了使用psexec之外)可以真正运行远程命令、变量和所有内容?我是否遗漏了一些简单的内容?

之所以出现这种情况,是因为您在创建脚本块时使用了双引号字符串$env:COMPUTERNAME在创建脚本块之前正在扩展为本地计算机名。如果使用单引号字符串,$env:COMPUTERNAME将作为文本文本在脚本块中传递,并且在远程计算机上执行之前不会进行扩展。因此,当您从字符串创建脚本块以便在远程计算机上执行时,当您想在脚本块中使用局部变量时,使用可扩展(双引号)字符串,当您想使用远程计算机上的变量时,使用不可扩展(单引号)字符串

$session = New-PSSession -ComputerName TO-MACHINE
$script = [ScriptBlock]::Create('$env:COMPUTERNAME')
Invoke-Command -session $session -scriptBlock $script
如果要在同一个脚本块中混合和匹配,请使用可扩展字符串,然后在所有远程变量引用上用反勾号转义$:

$session = New-PSSession -ComputerName TO-MACHINE 
$script = [ScriptBlock]::Create(" Write-output $env:Computername; Write-Output `$env:COMPUTERNAME ")
Invoke-Command -session $session -scriptBlock $script

您可以通过直接在代码中将
ScriptBlock
声明为
ScriptBlock
而不是
String
对象来避免这种情况。您只需将代码用大括号括起来即可。您可以将
ScriptBlock
对象存储在变量中,然后使用
-ScriptBlock
参数像以前一样将其传递到
Invoke命令中

$ScriptBlock = {
    $Program = 'c:\MyProgram.exe';
    Start-Process -Wait -FilePath $Program -ArgumentList 'args go here';

    Write-Host -Object "Write-Host Machine name is $env:COMPUTERNAME";
    }

Invoke-Command -ComputerName to-machine -ScriptBlock $ScriptBlock;

注意:您不必手动创建PowerShell远程处理会话<代码>调用命令
将为您解决此问题,除非您特别想让它们在后台打开。

如果我远程运行脚本,该怎么办?即使我正在运行的脚本位于不同的框中,它仍然会在FROM-MACHINE的上下文中报告变量。您是否测试了我发布的第二个脚本?它应该首先返回本地机器名,然后返回远程机器名。该脚本是在本地机器上运行还是在远程机器上运行?如果它在本地机器上,我会使用Invoke命令-FilePath。如果它在远程计算机上,则对字符串单引号,或者直接传递脚本块。