1

Say I'm passing a function as a parameter, is there a way to find out the name of the passed function through introspection in powershell? Or do I just have to pass it along with the rest of the parameters?

(without calling the function in question)

1 Answer 1

1

The linked question tries to pass a function by name, as a string, in which case the answer is obvious: the argument itself is the function name.

In case a script block is passed instead, you can use the following technique:

function get-ScriptBlockCommandName {

  param(
   [scriptblock] $ScriptBlock,
   [switch] $Expand 
  )

  # Using the script block's AST, extract the first command name / path token.
  $commandName = $ScriptBlock.Ast.EndBlock.
    Statements[0].PipelineElements.CommandElements[0].Extent.Text

  # Expand (interpolate) the raw name, if requested.
  if ($Expand) {
    $commandName = $ExecutionContext.InvokeCommand.ExpandString($commandName) 
  }

  # Remove outer quoting, if present.
  if ($commandName -match '^([''"])(.+)\1$') {
    $commandName = $Matches[2]
    if ($Matches[1] -eq "'") { $commandName = $commandName -replace "''", "'" }
  } 

  # Output
  $commandName

}

The function returns the (first) command name / path that is called from inside the script block.

Caveats:

  • An error will occur if you pass an expression (e.g., 1 + 2) as the first statement inside the script block.

  • Only the first command is analyzed (and its command name / path returned), whereas there is no limit to how many statements you can place inside a script block.

  • By default, if the command name / path is constructed from variables / other commands, these are not expanded (interpolated), given that doing so can result in execution of commands; to opt into expansion, use the -Expand switch.

Example calls:

PS> get-ScriptBlockCommandName { foo -bar baz -more stuff }
foo

This also works with quoted names / paths (note how & must then be used to invoke the command):

PS> get-ScriptBlockCommandName { & '/dir name/foo' -bar baz -more stuff }
/dir name/foo

However, to avoid potentially unwanted execution of commands, the command name / path is returned as-is, with variable references and subexpressions unexpanded.
You can opt to have these expanded by passing -Expand:

PS> get-ScriptBlockCommandName { & "$HOME/scripts/foo.ps1" -bar baz  } -Expand
C:/Users/jdoe/scripts.ps1  # e.g.
Sign up to request clarification or add additional context in comments.

Comments

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.