PowerShell Invoke-Command变量传入及修改后回传方法
问题根因
- PowerShell远程PSSession和本地会话是完全隔离的独立运行环境,脚本块内的变量修改不会自动同步回本地,跨会话数据传递必须显式传参、显式返回结果
- 原代码存在以下直接错误:
- 字符串值
Jos/Jon未加引号,会被PowerShell识别为命令名触发报错 -ArgumentList传入了2个参数,但脚本块Param块仅定义了1个入参,$fullname参数未被正确接收- 远程脚本块未显式输出需要回传的变量,本地也没有定义变量接收远程执行的返回结果
- 输出命令错误:不存在
write-out这个cmdlet,正确的输出命令为Write-Output - 指定
-JobName参数时,命令默认以异步后台作业形式运行,不等待执行完成、不调用Receive-Job无法获取执行结果
- 字符串值
正确代码实现
同步执行模式(最常用,不需要异步后台运行)
直接同步执行远程命令,接收返回的封装对象即可:
# 本地初始化变量,字符串值必须加引号 $myfirstname = "Jos" # 创建远程会话 $sess = New-PSSession -Computername "superdooperkompooter.domain.local" # 执行远程命令,将返回结果赋值给本地变量接收 $remoteResult = Invoke-Command -Session $sess -ScriptBlock { # 定义入参接收传入的本地变量 Param($passedFirstname) # 执行业务逻辑、修改变量 $modifiedFirstname = "Jon" $fullname = @( $modifiedFirstname, "Try", "Feckta" ) # 把所有需要回传的变量封装为自定义对象输出,会自动返回到本地调用端 [PSCustomObject]@{ MyFirstName = $modifiedFirstname FullName = $fullname } } -ArgumentList $myfirstname # 执行完成后移除远程会话,释放资源 Remove-PSSession $sess # 从返回结果中取值赋值给本地变量 $myfirstname = $remoteResult.MyFirstName $fullname = $remoteResult.FullName # 验证输出 Write-Output $myfirstname Write-Output $fullname
如果使用PowerShell 3.0及以上版本,可以用$using:语法简化传参,不需要写Param和-ArgumentList:
$myfirstname = "Jos" $sess = New-PSSession -Computername "superdooperkompooter.domain.local" $remoteResult = Invoke-Command -Session $sess -ScriptBlock { # 直接通过$using:作用域引用本地变量,拿到的是本地变量的拷贝 $localFirstnameCopy = $using:myfirstname $modifiedFirstname = "Jon" $fullname = @($modifiedFirstname, "Try", "Feckta") [PSCustomObject]@{ MyFirstName = $modifiedFirstname FullName = $fullname } } Remove-PSSession $sess $myfirstname = $remoteResult.MyFirstName $fullname = $remoteResult.FullName
异步后台作业模式(使用-JobName参数时)
如果需要以异步后台作业方式执行,需要等待作业完成后通过Receive-Job获取结果:
$myfirstname = "Jos" $sess = New-PSSession -Computername "superdooperkompooter.domain.local" # 启动远程后台作业,加-AsJob参数返回作业对象 $job = Invoke-Command -JobName whatsmyname -Session $sess -ScriptBlock { Param($passedFirstname) $modifiedFirstname = "Jon" $fullname = @($modifiedFirstname, "Try", "Feckta") [PSCustomObject]@{ MyFirstName = $modifiedFirstname FullName = $fullname } } -ArgumentList $myfirstname -AsJob # 阻塞等待作业执行完成 Wait-Job $job | Out-Null # 接收作业执行结果 $remoteResult = Receive-Job $job # 清理作业和远程会话 Remove-Job $job Remove-PSSession $sess # 本地使用返回值 $myfirstname = $remoteResult.MyFirstName $fullname = $remoteResult.FullName
关键注意事项
- 所有传入远程会话的参数都是值拷贝,远程侧对入参的修改不会影响本地原变量
- 所有需要回传本地的数据,必须在远程脚本块中显式输出,推荐封装为
[PSCustomObject]一次性回传多个变量,避免多输出流数据混乱 - 未手动移除的PSSession会保留远程侧上次执行产生的变量,但依然需要显式输出才能将变量值传递回本地
内容的提问来源于stack exchange,提问作者Coffee Black
相关产品推荐
相关产品推荐

