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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.