Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve variables in a Powershell script block

Tags:

powershell

Given I have:

$a = "world"
$b = { write-host "hello $a" }

How do I get the resolved text of the script block, which should be the entre string including write-host:

write-host "hello world"

UPDATE: additional clarifications

If you just print $b you get the variable and not the resolved value

write-host "hello $a"

If you execute the script block with & $b you get the printed value, not the contents of the script block:

hello world

This question is seeking a string containing the contents of the script block with the evaluated variables, which is:

write-host "hello world"
like image 378
alastairtree Avatar asked Mar 08 '19 12:03

alastairtree


1 Answers

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.

like image 80
AdminOfThings Avatar answered Sep 25 '22 07:09

AdminOfThings