You don't really need a predicate for this, with just a scriptblock would do but in this case you just pass a scriptblock as the Func<T, TResult>
argument instead of passing the name of your function, then that scriptblock is coerced into your predicate.
Note that your predicate as you have in your question is currently taking a bool
as input and outputting an int32
, I believe you're looking for the other way around, thus [Func[int, bool]]
instead of [Func[bool, int]]
.
function Test-Execution {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[int] $myValue,
[Parameter(Mandatory = $true, Position = 1)]
[Func[int, bool]] $myFunc
)
process {
if ($myFunc.Invoke($myValue)) { 'Yes' }
else { 'No' }
}
}
1..5 | Test-Execution -myFunc { $myValue -lt 3 }
Also, even though this works, you should actually evaluate using $args[0]
in your predicate instead of $myValue
since $args[0]
represents the first argument passed to the predicate:
1..5 | Test-Execution -myFunc { $args[0] -lt 3 }
If you want to use $_
instead of $args[0]
to resemble the current object passed through the pipeline you can use the call operator &
but in that case your function would work only from pipeline:
function Test-Execution {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[int] $myValue,
[Parameter(Mandatory = $true, Position = 1)]
[scriptblock] $myFunc
)
process {
if (& $myFunc) {
return 'Yes'
}
'No'
}
}
1..5 | Test-Execution -myFunc { $_ -lt 3 }
An alternative to evaluate using $_
as your argument even if the function was not receiving input from pipeline would be to use InvokeWithContext
, for instance (note that here we change the input object to [int[]] $myValue
and also add a loop):
function Test-Execution {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[int[]] $myValue,
[Parameter(Mandatory = $true, Position = 1)]
[scriptblock] $myFunc
)
process {
foreach($value in $myValue) {
if($myFunc.InvokeWithContext($null, [psvariable]::new('_', $value)[0])) {
'Yes'
continue
}
'No'
}
}
}
# now both ways work using this method, positional binding:
Test-Execution (1..5) -myFunc { $_ -lt 3 }
# and pipeline processing:
1..5 | Test-Execution -myFunc { $_ -lt 3 }