0

In PowerShell I can pass a parameter if I create a closure with param syntax:

$hello = { param($name) "Hello $name"}
& $hello "World!"

>hello.ps1
Hello World!

When I try this with function syntax I get into trouble:

function hello($n) { { "Hello $n" }.GetNewClosure() }

$doit = hello

& $doit "World!"

>functionclosure.ps1
Hello 

I managed to fix this by giving the parameter earlier:

function hello($n) { {"Hello $n"}.GetNewClosure()  }

$doit = hello "World"

& $doit

>functionclosure2.ps1
Hello World

Is there a way to pass a parameter to a function from the & call operator line?

2
  • 1
    You've written a function that takes a parameter and then creates a closure using that parameter. It seems like you want a function that returns a closure that takes a parameter -- but that's the same as your first example, and function hello { { param($n) "Hello $n"} } would do that. You'd invoke that as & (hello) "world". On the other hand, if you want to have a function as a closure you can invoke, ${function:hello} would do that (i.e. function hello($n) { "Hello $n" }; $doit = ${function:hello}; & $doit "World"). Commented Sep 25, 2020 at 13:33
  • May I edit this into an answer? @JeroenMostert Commented Sep 25, 2020 at 13:42

2 Answers 2

1

Is there a way to pass a parameter to a function from the & call operator line?

The call (also known as invocation or &) operator is generally used to execute content in a string, which we do when there is a long file path or a path with spaces in the name, or when we are dynamically building a string to execute.

Now, in this case, Using GetNewClosure() alters a function to instead return a scriptblock as the output type. That Scriptblock must be invoked using the Call operator, so this is a valid usage of the Call operator.

Back to your question then, yes, you can control the order of execution using paranthesis and pass a parameter to a function which returns a closure from the call line like this:

& (hello stephen)

However, this is pretty confusing in action as closures maintain their own separate scope and in more than ten years of enterprise automation projects, I never saw them used. It might be more confusion than it's worth to go down this route.

Prehaps a simpler approach might be:

function hello($name) { "WithinFunction: Hello $name"}
$do = 'hello "world"'
PS> $do
hello "world"
#invoke
PS> invoke-expression $do
WithinFunction: Hello world

Additional reading on closures by the man himself who implemented it in PowerShell here. https://devblogs.microsoft.com/scripting/closures-in-powershell/

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

3 Comments

Unlike the call operator, Invoke-Expression will accept any old thing that can be parsed as a script, which is very flexible but also dangerous. It should generally be avoided if there's another way of doing things, as it's very easy to end up executing things that are not supposed to be executed (when user input is involved, for example). You also run into potential trouble with quoting input values that way.
"and in more than ten years of enterprise automation projects, I never saw them used" --- or why I keep coming here. I cannot learn this from books, blog entries and exercises alone.
It's true, Gergely, I thought about writing a blog post on them, because each time you run a function which returns a scriptblock with .GetNewClosure() it runs within it's own variable scope. Very useful technique.
0

Jeroen Mostert wrote this as a comment:

You've written a function that takes a parameter and then creates a closure using that parameter. It seems like you want a function that returns a closure that takes a parameter -- but that's the same as your first example, and

function hello { { param($n) "Hello $n"} } 

would do that. You'd invoke that as

& (hello) "world"

On the other hand, if you want to have a function as a closure you can invoke,

${function:hello} 

would do that, i.e.

function hello($n) { "Hello $n" }; 
$doit = ${function:hello}; 
& $doit "World"

2 Comments

It would probably be better if you customized this to what you actually ended up using/needing (which your question didn't make very clear either). In particular the first construct (a function returning a closure) would be pretty unusual. (Also, mind the syntax, the last line is now wrong.)
I started PowerShell recently, my purpose is to learn its workings, no real application yet.

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.