Writing a function with Action in PowerShell

Tsuyoshi Ushio
2 min readOct 3, 2022

--

I wanted to write a function that has an action parameter. The goal is to write functions that have the following features:

  • Implement a dry-run feature
  • Print the command with resolved variables

For example,

Run({echo "hello $some"});

Result

some = “world”

[Command] echo "hello world"
hello world

If you configure dry-run

[Command] echo "hello world"

How to pass an action

Write a parameter. No special consideration required.

function Run {
param($action)
:
}

Next question comes to mind is, which type is it? It is ScriptBlock type. I didn’t know the type, however, it looks better approach than System.Action in PowerShell.

function Run {
param($action)
echo $action.GetType()
}
Run({echo "hello $dryRun"})

Result

IsPublic IsSerial Name                                     BaseType
-------- -------- ---- --------
True True ScriptBlock System.Object

Defines what a script block is and explains how to use script blocks in the PowerShell programming language.

For more details, refer to the following official documentation.

about Script Blocks — PowerShell | Microsoft Learn

How to run Script Block

Use the Script Block like following:

$a = {Get-Service BITS}
Invoke-Command -ScriptBlock $a

Define the Script Block with {...} For Execution, you can use Invoke-Command Command let. For simplify the command, you can use invoke()method as well.

Invoke-Command -ScriptBlock $action
$action.Invoke()

How to substitute variables?

ScriptBlock.ToString() method returns the ScriptBlock commands.

$some = "world"
$action = { echo "hello $some" }
echo $action.ToString()

Result

echo "hello $some"

I want to substitute some as world.

Use the $ExecutionContext.InvokeCommand.ExpandString()

$displayExecution = $ExecutionContext.InvokeCommand.ExpandString($action.ToString())
echo $displayExecution

Everything you wanted to know about variable substitution in strings — PowerShell | Microsoft Learn

Result

echo "hello world"

I’ve got something I wanted.

param($dryRun = "false")
function Run {
param($action)
$displayExecution = $ExecutionContext.InvokeCommand.ExpandString($action.ToString())
echo "[Command] $dispalyExecution"
if ($dryRun -eq "false") {
$action.Invoke()
}
}
$some = "world"Run({echo "hello $some"})

Result

> .\actionSpike.ps1
[Command] echo "hello world"
hello world
> .\actionSpike.ps1 -dryRun "true"
[Command] echo "hello world"

--

--