1

I'm trying to dynamically generate functions in PowerShell that are intended to act similarly to command aliases in bash etc.

In essence the functions are supposed to be generated from a string array that specify the alias names.

e.g.:

$commands = "build", "rebuild", "clean", "analyze"

I figured out how to dynamically create functions using 'New-Item -Path function: ..' however I'm unable to get a variable inside the function body ("$funcname") to expand to its current value. Instead it always adds $funcname to the function body which then reads the value that remains in the variable at runtime later.

How can I force $funcname to expand to its value at declaration time of the function body?

Here is the example:

$commands = "build", "rebuild", "clean", "analyze"

foreach($cmd in $commands)
{
    $funcname="$cmd"
    $body = { echo "$funcname" @args } # instead of 'echo' a script will be called
    New-Item -Path function: -Name "$funcname" -Value $body -Force
}

Output:

 > build "test"
analyze
test
 > rebuild "test"
analyze
test
...

This is the function items content and the reason why it behaves that way:

 > $function:build
echo $funcname @args
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
so_below
  • 15
  • 4

1 Answers1

3

PowerShell variables are dynamically scoped, meaning variable resolution is deferred until runtime - meaning the value of $funcname, when evaluated, will always be the last value assigned to it (in this case "analyze").

To get around this, construct a closure:

$commands = "build", "rebuild", "clean", "analyze"

foreach($cmd in $commands)
{
    $funcname="$cmd"
    $body = { echo "$funcname" @args }.GetNewClosure()
    New-Item -Path function: -Name "$funcname" -Value $body -Force
}

GetNewClosure() will capture the value of $funcname from the calling scope and store it in a dynamic module which is then attached to the scriptblock. When you later invoke the script block, the variable resolution routine will run into the dynamic-module-stored copy of $funcname and resolve the expected value.

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206