How to Assign Variable as Expression or Function then Invoke It

Problem

In any programming language, typically there is a feature called anonymous function where it allows us to store expression or function into a variable. The function, then, can be invoked through the variable.

For example, in JavaScript we can create anonymous function as follows:


const x = function (a, b) {return a + b};
let z = x(4, 3);

Similarly in PowerShell, we can also create anonymous function through a feature called Script Block.

Solution

A Script Block is a group of statements or expressions that can be used together as a single unit. The statements or expressions in Script Block must be enclosed with braces {}. The script block can receive parameters and return values.


{ <statements/expressions>  }

Using Script Block

For example, we want to put Get-Random cmdlet into Script Block, then invoke the function through the assigned variable.


$func = { Get-Random }
Invoke-Command -ScriptBlock $func

The Invoke-Command statement will execute the Script Block and generate random number.

We can also using Script Block for our own function such as:


Function Test() {    
    $FullName = [PSCustomObject]@{
        FirstName = "John"
        LastName  = "Doe"
    }

    return $FullName
}

$func = { Test }
Invoke-Command -ScriptBlock $func

Please remember above script will behave differently if the function is directly enclosed inside Script Block like below:


$func = { 
    Function Test() {    
        $FullName = [PSCustomObject]@{
            FirstName = "John"
            LastName  = "Doe"
        }

        return $FullName
    } }
Invoke-Command -ScriptBlock $func

The above script won’t generate random number unlike the former. The reason is Script Block works for anonymous function inside braces {}.

So, to make it work, either we enclose Test function without body inside braces like former script or remove the function name to make it anonymous, then enclose it with braces {} as follows:


$func = { 
    param($firstName, $lastName)
    $FullName = [PSCustomObject]@{
        FirstName = $firstName
        LastName  = $lastName
    }

    return $FullName
}
Invoke-Command -ScriptBlock $func -ArgumentList "John", "Doe"

Executing Script Block without storing it into a variable

We can execute Script Block directly without having to store into a variable as follows:


Invoke-Command -ScriptBlock { 
    param($firstName, $lastName)
    $FullName = [PSCustomObject]@{
        FirstName = $firstName
        LastName  = $lastName
    }

    return $FullName
} -ArgumentList "John", "Doe"

Alternatives for Executing Script Block

Besides using Invoke-Command, we can also use call operator &.


$func = { 
    param($firstName, $lastName)
    $FullName = [PSCustomObject]@{
        FirstName = $firstName
        LastName  = $lastName
    }

    return $FullName
}
& $func -firstName "John" -lastName "Doe"

Conclusion

In conclusion, Script Block enables us to create anonymous function. We can store Script Block in a variable or not and to execute we can use Invoke-Command or call operator &.