Quick hit: Dynamic Where-Object calls

On occasion, you might want to build up a call to Where-Object that changes based on your runtime environment.  Perhaps you have to iterate over a huge collection, or you have an expensive statement to evaluate that doesn’t need to run in all scenarios.  This post will illustrate how to build up a dynamic call to Where-Object using example code from Get-Type.

The ScriptBlock

So we want to modify what runs in Where-Object.  We know the standard call is Where-Object {<# Something #> }, so we’ll dive into the help to find out what parameter that scriptblock is.  We want to find a parameter with Position 0 or 1 that takes a ScriptBlock – we dive in and find this is the FilterScript parameter:

Get-Help Where-Object -Full

Where

Now, we want to create the scriptblock for this parameter dynamically.  If we search around, we might find that you can convert a string to a scriptblock using the create method from the System.Management.Automation.ScriptBlock class.  It sounds complicated, but the code is pretty straightforward:

$ScriptBlock = [scriptblock]::Create( $String )

Okay!  At this point, we know what parameter takes in the scriptblock, we know how to create a scriptblock from text, and hopefully, we know how to work with strings.

Putting it all together

In Get-Type, we provide a few parameters to allow filtering on the returned types.  If these are set to *, we don’t want to evaluate them to the where clause.  If they aren’t set to *, we want to add a statement to the where clause.

There are many ways to skin this cat; we’re going to build up an array of statements and join them with –and.  You can build your strings as desired.

#Build the Where array            
$WhereArray = @()            
            
#If anything but the default * was provided, evaluate these with like comparison            
if($Module -ne "*"){$WhereArray += '$_.Module -like $Module'}            
if($Assembly -ne "*"){$WhereArray += '$_.Assembly -like $Assembly'}            
if($FullName -ne "*"){$WhereArray += '$_.FullName -like $FullName'}            
if($Namespace -ne "*"){$WhereArray += '$_.Namespace -like $Namespace'}            
if($BaseType -ne "*"){$WhereArray += '$_.BaseType -like $BaseType'}            
            
#Build the where array into a string by joining each statement with -and            
$WhereString = $WhereArray -Join " -and "            
            
#Create the scriptblock with your final string            
$WhereBlock = [scriptblock]::Create( $WhereString )

At this point, we have the scriptblock created!  If we call Get-Type with –Verbose, we can see what the scriptblock looks like depending on the parameters we call at run time:

Where2

That’s about it!  We illustrated how to build up a scriptblock dynamically and used it with Where-Object – keep in mind you could use this for other scenarios where you need to build a scriptblock up in pieces.

Edit: A quick follow-up – There are situations where your scriptblock really needs to be dynamically generated.  The example itself did not need it for performance or functionality; simplicity and clarity of code would generally take priority, I was just curious.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s