我有一个接受[scriptblock]
参数的自定义函数,在将脚本块发送到远程进程以进行反序列化和调用之前,使用[System.Management.Automation.PSSerializer]::Serialize()
对其进行了serailzed。远程进程无权访问本地变量。我想允许在函数调用中将变量放入scriptblock中,但是我会使用第二个参数$ArgumentList
来将参数\参数传递给scriptblock。我在System.Management.Automation.dll
浏览了Microsoft.PowerShell.Commands.InvokeCommandCommand
以查看我是否可以确定Invoke-command如何添加此功能,但我是C#的初学者并且无法弄明白。
如何在脚本块发送之前扩展它们中的变量?
本地序列化函数的一个示例:
Function Send-Command
{
param(
[scriptblock]$Scriptblock
)
[String]$Serialized = [System.Management.Automation.PSSerializer]::Serialize($Scriptblock)
[byte[]]$MessageBytes = [System.Text.Encoding]::UTF8.GetBytes($Serialized)
return $MessageBytes
}
另一方面:
[byte[]]$Serialized = [System.Text.Encoding]::UTF8.GetString($MessageBytes)
[String]$Deserialized = [System.Management.Automation.PSSerializer]::Deserialize($Serialized.ToString())
return $Deserialized
我用局部变量调用函数:
$String = "This is a Test"
Send-Command -Scriptblock {Write-Output $String }
另一方面:
Command: Write-Output $String
应输出:
Command: Write-Output "This is a Test"
答案 0 :(得分:1)
有一种反序列化ScriptBlock的方法。
您必须首先从字符串创建一个脚本块。 然后,您必须序列化绑定到作用域的所有变量。 之后,我们使用正则表达式将变量替换为有效载荷以反序列化其值。
反序列化代码时,它将在ScriptBlock中具有注入的代码以反序列化变量的值,因此它们保留了内容。 然后,您需要调用GetNewClosure()来从反序列化器范围中解除绑定变量(例如任何参数),然后在下一次调用中将其自由绑定。
此解决方案基于powershell DSC基础结构的作用。
Function Serialize-Command
{
param(
[scriptblock]$Scriptblock
)
$rxp = '\$using:(?<var>\w+)'
$ssb = $Scriptblock.ToString()
$cb = {
$v = (Get-Variable -Name $args[0].Groups['var'] -ValueOnly)
$ser = [System.Management.Automation.PSSerializer]::Serialize($v)
"`$([System.Management.Automation.PSSerializer]::Deserialize('{0}'))" -f $ser
}
$sb = [RegEx]::Replace($ssb, $rxp, $cb, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$Serialized = [System.Management.Automation.PSSerializer]::Serialize($sb)
[System.Text.Encoding]::UTF8.GetBytes($Serialized)
}
Function Deserialize-Command
{
param(
[byte[]]$ScriptblockString
)
$Serialized = [System.Text.Encoding]::UTF8.GetString($ScriptblockString)
$sb = [System.Management.Automation.PSSerializer]::Deserialize($Serialized.ToString())
[Scriptblock]::Create($sb).GetNewClosure()
}
$a = "is this what you wanted?"
$b = Serialize-Command { "test $using:a" }
$a = "okay"
$c = Deserialize-Command $b
$a = "right"
PS> & $c
is this what you wanted?
来源:
https://www.briantist.com/how-to/use-duplicate-dsc-script-resources-in-loop/
https://devblogs.microsoft.com/powershell/get-closure-with-getnewclosure/
答案 1 :(得分:0)
扩展变量的两种常用方法如下:
$VariableName
"$VariableName"
$($VariableName)
...但是还有其他考虑因素取决于你在做什么。
然而,你所问的,似乎与这篇文章非常相似:
Expand variable with scriptblock inside variable in a loop with runspaces
答案 2 :(得分:0)
使用PowerShell,我建议您执行以下操作:
为什么不将 Invoke-Command 与脚本块一起使用来在远程计算机上运行脚本块?您可以将两者与$ 使用: LocalVariableName 语句结合使用,以从远程主机访问局部变量,或者如上所述进行局部变量扩展,甚至将两者结合使用。
我想应该是这样的:
$ScriptBlock = { Write-Output $using:Text } $Text = 'This is a test' function Send-Command { param ( [scriptblock] $ScriptBlock, [string] $ComputerName, [System.Management.Automation.PSCredential] $Credential ) Invoke-Command -ComputerName $Computername -ScriptBlock $ScriptBlock -Credential $Credential } $ComputerName = 'Server0123' $Credential = Get-Credential -Message "Enter credential for computer $($ComputerName)" Send-Command $ScriptBlock $ComputerName $Credential