EN VI

Powershell - How to detect if incoming pipe object is not a scalar object like a string or int?

2024-03-13 02:30:06
Powershell - How to detect if incoming pipe object is not a scalar object like a string or int?

I have a function that makes use of the fzf cli utility, I use it to interactively select a object (by selecting a value that belongs to one its properties)

Function SelectFZF-Object{
    param(
        [argumentcompletions('Name','BaseName','Extension','Parent','FullName','Title','Url')]
        [parameter(ValueFromPipelineByPropertyName)]
        [string]$DisplayProperty = "title",
        
        [String]$Limit = "50",
        [String]$mode = "-m",

        [Parameter(ValueFromPipeline)]
        $InputObect
        )
        begin{$collect = [System.Collections.Generic.List[object]]::new()}
        process{$collect.Add($InputObect)}
        end{$collect | ForEach-Object {$_."$DisplayProperty"} | fzf -e $mode | ForEach-Object {$collect | Where-Object $DisplayProperty -EQ $_}}
    }

While it works fine for objects that have multiple properties, it does not work for simple scalar values, so I cant do the following:

"foo", "bar", "baz" | SelectFZF-Object

I am for example, expecting to get bar returned to the output.

If I can just test the input object to find out if its a simple, flat or scalar value, then I can handle it accordingly, I have thus far not found anything though.

Solution:

You'll probably cover most use cases by simply testing whether the input value is either a [string], a [decimal], a [bigint], or of a primitive value type (eg. [int], [byte], [char], etc.):

$collect |ForEach-Object {
  if($_ -is [string] -or $_ -is [decimal] -or $_ -is [bigint] -or $_.GetType().IsPrimitive) {
    # skip dereferencing display-property
    $_
  }
  else {
    $_."$DisplayProperty"
  }
} | ...

Another approach, available in PowerShell 7, is to cast the $DisplayProperty argument to [pspropertyexpression] - this will afford the caller more flexibility, as it allows for calculated expressions:

param(
    [argumentcompletions('Name','BaseName','Extension','Parent','FullName','Title','Url')]
    [Parameter(ValueFromPipelineByPropertyName)]
    [pspropertyexpression]$DisplayProperty = $({ "$_" }),
    
    [String]$Limit = "50",
    [String]$mode = "-m",

    [Parameter(ValueFromPipeline)]
    $InputObject
)

# ...

end {
  $collect |ForEach-Object {
    $DisplayProperty.GetValues($_).Result
  } | ...
}

Now you can simply do:

"foo", "bar", "baz" |SelectFZF-Object

Or:

"foo", "bar", "baz" |SelectFZF-Object { $_.ToUpper() }
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login