1

If I create a PowerShell function with a parameter of type [scriptblock], which method is the best to execute the script block inside the function? And why?

I am aware of the following options:

  • . source operator
  • & (call) operator
  • Invoke-Expression

1 Answer 1

5

. runs the scriptblock in the current scope. & runs the scriptblock in a child scope (same as running the scripblock via its Invoke() method). Which one you want to use depends on the outcome you want to achieve.

Demonstration:

Running via Invoke() method:

PS C:\> $s = { $a = 2; $a }
PS C:\> $a = 1
PS C:\> $s.Invoke()
2
PS C:\> $a
1

Running via call operator:

PS C:\> $s = { $a = 2; $a }
PS C:\> $a = 1
PS C:\> & $s
2
PS C:\> $a
1

Running via dot-sourcing operator:

PS C:\> $s = { $a = 2; $a }
PS C:\> $a = 1
PS C:\> . $s
2
PS C:\> $a
2

If you need the scriptblock to modify something in the current scope: use the . operator. Otherwise use call operator or Invoke() method.

Do not use Invoke-Expression.

Sign up to request clarification or add additional context in comments.

5 Comments

I like the Invoke() method. I was unaware of that one. I think it make the code more readable. I think for my functions this will work in most cases. The scoping rules are subtle. I would have missed that and learned the hard way!
The script blocks I am running will need to share a few variables between them. So if I use the & (call) operator is there a recommended way to make these variables visible to multiple script blocks? Is $global: script the way to go in this case? I'm a little concerned about the . (source) operator because the script block code will share the same variables as the caller's scope which might lead to very tricky bugs.
@MatthewMacFarland If you want all the variables shared between scriptblocks it would be simpler to just use the . operator. If you want some variables shared between scriptblocks but not all of them you could use the global: or script: scope modifier. With that said, I wouldn't recommend actually doing this as it reeks of bad design.
@AngsarWiechers Interesting. So I definitely want to share only a couple of variables between the code in the various scripts blocks but I certainly don't want bad design either. Kinda stuck. Do you know of any references or blogs on a good design for this sort of situation?
Joking aside, no, I don't know of a good reference short of software engineering studies. What I can tell you is that scriptblocks are PowerShell's implementation of anonymous functions. Anonymous functions are very useful in some situations, but I think for what you seem to try to do classic functions with proper parametrization would be a better approach. You want a clear data flow through your code. Data flow via global variables is a mess and a pain to debug.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.