Where-Object
's params providing shorthands for builtin operators, one can skip the scriptblock and write:
Get-ChildItem | Where-Object { $_.Name -match '\.(txt|md)$' }
as:
Get-ChildItem | Where-Object Name -match '\.(txt|md)$'
Is there some way to apply the operator to entire object instead of one of its properties? I.e. how can I write similar shorthand to the following:
Get-ChildItem | ForEach-Object Name | Where-Object { $_ -match '\.(txt|md)$' }
A simple Where-Object -match '\.(txt|md)$'
fails with:
Where-Object: The specified operator requires both the -Property and -Value parameters. Provide values for both parameters, and then try the command again.
The -Value
is a red herring, since it positionally matches the regex. Looking at help, the -Property
for -Match
is not specified as optional, but I thought maybe some magic like *
or _
would work - alas they do not.
Indeed, as of PowerShell (Core) 7 v7.5.x, using simplified syntax with Where-Object
syntactically requires a property-name argument,[1] i.e. an argument that binds, typically positionally, to the -Property
parameter, in addition to requiring a switch named for a comparison operator (e.g., -match
) and a comparison value, i.e. an argument that binds, typically positionally, to the -Value
parameter.
Since you can therefore not omit a property name and given that there is no placeholder value that represents the input object as a whole, applying an operation to an object as a whole is not currently possible with simplified syntax, so the more verbose script block-based syntax ({ ... }
), via the typically positionally bound -FilterScript
parameter, must be used, where the current pipeline input object must be referred to via the automatic $_
variable or its alias, $PSItem
.
Indeed, it would be helpful if simplified syntax allowed omission of a -Property
argument to imply the intent to perform the comparison on the object as a whole, as it would allow simplifying this (script-block syntax):
# Note: -Name makes Get-ChildItem output file names only, i.e. *strings*
Get-ChildItem -Name | Where-Object { $_ -match '\.(txt|md)$' }
to (simplified syntax):
# WISHFUL THINKING as of PowerShell 7.5.x:
# Omitting the LHS (-Property argument) implies use of the whole object
Get-ChildItem -Name | Where-Object -match '\.(txt|md)$'
This enhancement (feature request) was first proposed in in GitHub issue #8357 in 2018. Alas, the discussion has stalled.
[1] You can verify this with Get-Command -Syntax Where-Object
: [-Property] <string>
, a notation described in the conceptual about_Command_Syntax help topic, indicates that while specifying the parameter name (-Property
) is optional - indicated by the [...]
enclosure - the parameter value (of type <string>
) is not, i.e. it is mandatory.
Note that even though the -Value
parameter is in effect mandatory, technically it is not, as the [...]
enclosure around both the parameter name and value type indicates: [[-Value] <Object>]
. Instead, the presence of a -Value
argument is enforced inside the command, producing the error shown in your question in its absence. Apparently, this approach was preferred to prompting for a missing value, which is what would happen if the parameter were formally marked as mandatory (you can see the prompt in action for -Property
if you provide neither a -Property
nor a -Value
argument; e.g. Where-Object -eq
).
It's not clear to me why this implementation was chosen; the only operator not requiring (or even accepting) a value is the inherently unary -Not
operator, but it is in a separate parameter set that simply doesn't include the -Value
parameter.