Andy Schneider
Andy Schneider

Reputation: 8684

PowerShell AST FindAll method take a scriptblock with $args[0]

I have been working with the PowerShell AST to create some custom rules for PSScriptAnalyzer.

In a lot of the example code for AST, there is one line that I don't understand. Here is an example.

First parse a file, in this case, the current open file in the ISE.

$AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: 
                  ParseInput($psISE.CurrentFile.Editor.Text, [ref]$null, [ref]$null)

This makes sense so far. Let's say that we want to look for all the ParameterAst objects. The code that I have seen to do this is below.

$params = $AbstractSyntaxTree.FindAll({$args[0] -is [System.Management.Automation.Language.ParameterAst]}, $true)

This line of code is calling FindAll and passing in a scriptblock, that seems to be acting as a filter, so that only ParameterAst objects are returned.

What I don't understand here is how $args[0] fits into this call. How are any parameters actually getting passed into the scriptblock when the FindAll method is invoked?

Upvotes: 3

Views: 1637

Answers (2)

mgr32
mgr32

Reputation: 386

FindAll method has following signature (from msdn):

public IEnumerable<Ast> FindAll (
    Func<Ast,bool> predicate,
    bool searchNestedScriptBlocks
)

So first argument is a delegate that takes Ast as input, and returns bool. In Powershell you can create such delegate like that:

$delegate = { param($ast) $ast -is [System.Management.Automation.Language.ParameterAst] }

Or without declaring parameter:

$delegate = { $args[0] -is [System.Management.Automation.Language.ParameterAst] }

FindAll method will then do something like that (pseudocode):

foreach ($node in $allNodes) {
    $shouldAdd = & $delegate $node  <-- this is how $node gets passed to your delegate
    if ($shouldAdd) {
       <add the node to the output list>
    }
}

Upvotes: 3

briantist
briantist

Reputation: 47832

Think of the scriptblock as an anonymous callback function.

It's really the same thing that happens when you use Where-Object { $someCondition }.

.FindAll finds all the (things) and for each one it calls the function you provided it. It's apparently expecting a [bool] result, and returning the objects that satisfied the conditions present in the callback.

In a function or script or scriptblock in powershell, you can have named parameters that are explicitly defined, or you can reference parameters without declaring them using the $args array, which is what's happening here.

Using a scriptblock as a callback is similar to using it for an event:

$Args

   Contains an array of the undeclared parameters and/or parameter
   values that are passed to a function, script, or script block.
   When you create a function, you can declare the parameters by using the
   param keyword or by adding a comma-separated list of parameters in
   parentheses after the function name.

   In an event action, the $Args variable contains objects that represent
   the event arguments of the event that is being processed.

Upvotes: 1

Related Questions