简体   繁体   中英

Using Powershell introspection to find the name of a function passed as a parameter?

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)

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 (eg, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM