如何在PowerShell中将脚本块存入变量并用于Invoke-Command
问题解决:Hyper-V中Invoke-Command使用ScriptBlock变量获取VM主机名失败
核心原因
你遇到的问题是变量解析时机错误:
- 直接写
{"$env:COMPUTERNAME"}时,这个脚本块会被完整传到目标VM,在VM的环境中才解析$env:COMPUTERNAME,得到的是VM自身的计算机名。 - 但你把
"$env:COMPUTERNAME"存成字符串变量时,这个赋值操作会立即在Hyper-V主机环境中解析$env:COMPUTERNAME,得到的是主机的计算机名。之后无论你把这个变量放到ScriptBlock里,还是用[ScriptBlock]::Create()转换,最终传到VM执行的都是已经解析好的主机名,而非VM的。
正确写法
写法1:直接定义ScriptBlock类型变量
直接把脚本块定义为[ScriptBlock]类型,避免提前解析:
# 直接创建ScriptBlock变量,不经过字符串中转 $scriptBlock = { $env:COMPUTERNAME } # 执行命令 Get-VM | Where-Object State -Eq 'Running' | ForEach-Object { Invoke-Command -VMName $_.Name -ScriptBlock $scriptBlock -Credential $cred '' # 空行分隔结果 }
写法2:用字符串创建ScriptBlock时,避免提前解析
如果必须通过字符串中转,要使用单引号包裹字符串(单引号内的变量不会被主机解析),再转换为ScriptBlock:
# 用单引号定义字符串,$env:COMPUTERNAME不会被主机提前解析 $scriptStr = '$env:COMPUTERNAME' $scriptBlock = [ScriptBlock]::Create($scriptStr) # 执行命令 Get-VM | Where-Object State -Eq 'Running' | ForEach-Object { Invoke-Command -VMName $_.Name -ScriptBlock $scriptBlock -Credential $cred '' }
为什么之前的尝试失败
$script="$env:COMPUTERNAME":赋值时主机直接解析$env:COMPUTERNAME为自身主机名,传到VM后输出的是主机名。[ScriptBlock]::create("$env:COMPUTERNAME"):同样,字符串里的$env:COMPUTERNAME已经被主机解析,生成的ScriptBlock实际是{ 主机名 },执行后自然不对。{"$script"}或{"$($script)"}:还是在主机端解析$script的值(主机名),传到VM输出的依然是主机名。
内容的提问来源于stack exchange,提问作者FrinkTheBrave
相关产品推荐
相关产品推荐

