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
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:
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.