As in the original question, if your entire scriptblock contents is not a string (but you want it to be) and you need variable substitution within the scriptblock, you can use the following:
$ExecutionContext.InvokeCommand.ExpandString($b)
Calling .InvokeCommand.ExpandString($b)
on the current execution context will use the variables in the current scope for substitution.
The following is one way to create a scripblock and retrieve its contents:
$a = "world"
$b = [ScriptBlock]::create("write-host hello $a")
$b
write-host hello world
You can use your scriptblock notation {}
as well to accomplish the same thing, but you need to use the &
call operator:
$a = "world"
$b = {"write-host hello $a"}
& $b
write-host hello world
A feature to using the method above is that if you change the value of $a
at any time and then call the scriptblock again, the output will be updated like so:
$a = "world"
$b = {"write-host hello $a"}
& $b
write-host hello world
$a = "hi"
& $b
write-host hello hi
The GetNewClosure()
method can be used to create a clone of the scriptblock above to take a theoretical snapshot of the scriptblock's current evaluation. It will be immune to the changing of the $a
value later the code:
$b = {"write-host hello $a"}.GetNewClosure()
& $b
write-host hello world
$a = "new world"
& $b
write-host hello world
The {}
notation denotes a scriptblock object as you probably already know. That can be passed into Invoke-Command
, which opens up other options. You can also create parameters inside of the scriptblock that can be passed in later. See about_Script_Blocks for more information.
Invoke-Command -ScriptBlock $b
output =hello world
– Glorify$ExecutionContext.InvokeCommand.ExpandString($b)
– Cytolysin