honzajscz
honzajscz

Reputation: 3107

PowerShell implicit value property in where-object

Is it possible to convert following where PS script block

$env:Path -split ";" | where {$_ -like "c:\Program*"}

to a where comparison statement looking like

$env:Path -split ";" | where ???WHAT HERE??? -like "c:\Program*"

What I need is something that would replace the implicit $_ variable from the first statment.

Edit: My intention is pure curiosity. I prefer to use the second way of the where-object cmdlet, however, I do not know how to address the pipe value directly on the left side of the -like operator

Edit2: What is a comparison statement? A comparison statement is much more like natural language. Comparison statements were introduced in Windows PowerShell 3.0. An example:

Get-Process | Where-Object PriorityClass -eq "Normal"

Source: Where-Object on MSDN

Upvotes: 4

Views: 621

Answers (3)

Bacon Bits
Bacon Bits

Reputation: 32200

Is it possible to convert following where PS script block

$env:Path -split ";" | where {$_ -like "c:\Program*"}

to a where comparison statement looking like

$env:Path -split ";" | where ???WHAT HERE??? -like "c:\Program*"

No, that is not possible.

There are two modes for Where-Object. Fully expressed, one looks like this:

ls | Where-Object -FilterScript { $_.Name -eq 'File.txt' }

Here, we're writing a scriptblock that contains an expression that is evaluated on every item.

The other mode, fully expressed, actually looks like this.

ls | Where-Object -Property Name -Value File.txt -Eq

Note that the -Eq here is a parameter and not an operator. We're calling a command, not writing an expression in a scriptblock here. And I know what you're thinking. "But to work that way, the command would need to have a different parameter set for every conceivable operator!" And that's exactly what they do!

Where-Object [-InputObject <PSObject>] [-Property] <String> [[-Value] <Object>] [-EQ] [<CommonParameters>]
Where-Object [-InputObject <PSObject>] [-Property] <String> [[-Value] <Object>] [-NE] [<CommonParameters>]
Where-Object [-InputObject <PSObject>] [-Property] <String> [[-Value] <Object>] [-LT] [<CommonParameters>]
[...]

The -InputObject parameter is the value from the pipeline. -Property is the first positional parameter. -Value is the second positional parameter.

The problem is that the -Property parameter is mandatory. You can't call this command without specifying a parameter name and there's no property name that means "this object".

Upvotes: 3

f6a4
f6a4

Reputation: 1782

You could write your own pipe function like this:

    Add-Type -AssemblyName System.Collections

    function where-special { 
    [cmdletbinding()]

    param(
        [Parameter(ValueFromPipeline=$true)]
        [object[]]$piped,
        [Parameter(Position=1, ParameterSetName="eq")]
        [object]$eq,
        [Parameter(Position=1, ParameterSetName="like")]
        [object]$like,
        [Parameter(Position=1, ParameterSetName="match")]
        [object]$match )

    Begin {
        [System.Collections.Generic.List[object]]$found = @()

        $toDo = [Scriptblock]::Create( 'if( $piped -' + $PSCmdlet.ParameterSetName + ' $' + $PSCmdlet.ParameterSetName + ') { $found.Add( $piped ) }' )
    }

    Process  {

        & $toDo
    }

    End {
        return $found.ToArray()
    }
}


$env:Path -split ";" | where-special -like 'C:\Windows' 

Upvotes: 1

trebleCode
trebleCode

Reputation: 2318

$env:Path -split ";" | where { $_.StartsWith("C:\Program") -eq $True }

Upvotes: -1

Related Questions