I have an Advanced Function that is designed to stream packets to me and they come into my NIC, similar to Wireshark. The problem is that I want to implement a -Filter parameter in my function rather than piping the whole function to Where-Object.
At first glance, I thought I would get away with setting a a $filter paramater as a scriptblock and where I am streaming the object in one at a time, piping THAT object to Where-Object like this: $Packet Where-Object -FilterScript $Filter
This however didn’t work as I had planned. I am going to spare the long explanation of trial and error for the time being. Does anyone know of resources out there for implementing my own -Filter Parameter? I have searched for the last hour and a half and had no luck.
So, I am completely not understanding what you’re asking. I think you probably need to share some code snippets of what you’re doing.
As far as implementing your own -Filter parameter… that’s easy. Doing something with it depends entirely on what your code is doing. I mean, there’s no built-in “here’s how to write a filter.” For example,
function foo {
param([scriptblock]$filter)
Get-Something | Where-Object -Filter $filter
}
Essentially works, but I’ve no idea if that’s meaningful in what you’re trying to do. And I should point out that this is not functionally all that different from piping the whole function to Where-Object, if your function is normally outputting one object at a time to the pipeline. A filter is really only meaningful in a function if it can prevent data from entering PowerShell at all, a la the -Filter on Get-WmiObject. Once you’re “filtering using PowerShell,” it doesn’t necessarily matter where you do it (again, all things being equal - not seeing your code it’s hard to make definitive statements).
I doubt the performance will be any better than using Where-Object, but you can do something like this:
function YourFunction
{
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)]
$InputObject,
[scriptblock]
$Filter
)
process
{
if ($null -eq $Filter -or $Filter.Invoke($InputObject))
{
# Object passed your filter (or no filter was specified); do something here
$InputObject
}
}
}
With the code written like that, the two following commands would produce identical results:
Never Mind. I tried an additional test and it succeeded. So the Fundamental question that I was asking has been solved. This is the test that I ran and succeeded with:
Function Test {
[CmdletBinding()]
param
(
[scriptblock]$Filter
)
Begin {
}
Process {
$Packet = New-Object PSObject -Property @{
Name = "MyStuff"
Address = "1.1.1.1"
Port = 135
Notes = "This is a test."
}
If ($Filter) {
$Packet | Select-Object Name,Address,Port,Notes | Where-Object $Filter
}
Else {
$Packet | Select-Object Name,Address,Port,Notes
}
}
End {
}
}
Test -Filter {$_.Name -like “Stuff”}
No Results
Test -Filter {$_.Name -like “Stuff”}
Results
I lied… There is a followup question that comes to mind. With the -filter in Get-ADUser, I can specify {SamAccountName -eq “MyUserName”}
Rather than {$_.SamAccountName -eq “MyUserName”}
Does anyone have an idea on how I can mimic that functionality in the test code above?
Get-ADUser’s filter is much more complex. It accepts a string, not a ScriptBlock, and it has code to parse that string and turn it into an LDAP filter behind the scenes. Writing your own code to parse a complex expression and evaulate it against an input object would be a lot of work, with the only real benefit being that the user can save three characters of typing by eliminating $_.
I understand. I guess the bigger concern of mine is that trying to remember several different -filter syntax’s for different commands might be a little too much with their already high stress from a heavy workload. I am just trying to match it to AD because it is what they are used to. Now that I know there is no “easy” way to do it, I will likley go on a glorious adventure developing a code snippet to handle it in the way that I desire.