You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Request: Where-Object used without -Property works on "the object" #8357
These don't work, but it would be nice if they did:
PS C:\> 'test.txt', '', 'example.xml' | where -match 'txt'
where-object : The specified operator requires both the -Property and -Value parameters.
PS C:\> 1..10 | ? -gt $x
?: The specified operator requires both the -Property and -Value parameters.
but integers and strings have no -Property way to access their values. Select-String helps for text, but outputs MatchInfo not String. And doesn't help for any of the operators except -match.
Used without -Property it could implicitly use $_ with whatever casting that implies, the same as if you'd written { $_ -operator 'value' } as the filterscript.
and that would implicitly act like ? { $_ } which does a boolean cast on the object and passes true ones.
Reacted by Josh Cotton, Michael Klement, Rain Sallow (/u/ta11ow), wisemoth, Todor Mitskovski, Keith Hill, Steven Wight (PoSHYoungTeam) and Dominik Kowalski
I'm not sold on that part either, but where { $_ } is pretty cryptic, and where -property x -eq $true casts the wrong way, $true gets cast to string, instead of the property being cast to bool, so that looks like it would work but it "surprisingly" doesn't.
The concept "filter things which are truthy" is useful, and it sort of falls out of this request - with a property it maps to {$_.Prop -op $value}, then with this request if you don't specify -property it works on "the object in the pipeline" and maps to {$_ -op $value}, and then if you don't specify the operation either it would map to just {$_}. This part could be separated out into a different request for a way to say something like where-object -Truthy.
I am still missing the proposed syntax, because it would allow for using less parentheses. A command followed by a pipeline is not "overloaded", unlike a command followed by an operator. In that case the operator is considered a parameter of the command, and parentheses must be used:
HumanEquivalentUnit The inability to specify the whole object has annoyed me for years. I'd always expected that we would use -Property _ to mean the whole object but that never got implemented. Of course there's no reason not to do it now. So
1..10|where_-gt5
would be equivalent to
1..10|where {$_-gt5}
Reacted by Rain Sallow (/u/ta11ow), Keith Hill, iRon7 and HumanEquivalentUnit
That's not a bad idea Bruce Payette (@BrucePay) but it does prevent anyone from making use of a property actually named_ (i.e., | where {$_._ -gt 5} would be rendered impossible to work with using the parameter syntax).
Rain Sallow (/u/ta11ow) (@vexx32) Practically speaking, the likelihood of a property named '_' is miniscule. And should it occur, you can always use the scriptblock form of the command. After all, the property syntax is a very small subset of what you can do in a scriptblock. Sso I don't see this as a significant concern.
Certainly, but I don't see why Where _ -gt 5 is better than Where-Object -gt 5; arguably the latter is more clear in intent, and doesn't risk being confused for an (admittedly unwise) property name. 😄
Bruce Payette (@BrucePay) I like the use of _ well enough; right now, gci | where length filters on the property Length being truthy, so |where _ is a valid instruction. Clashing with properties called _ doesn't bother me, but special casing -Property _ to mean "the object" feels weird, is there anywhere else that meaning exists? Would people then expect it to work with other cmdlets that have a -Property?
What do you think of the idea of it being valid to use where-object with no parameters at all?
It's growing on me to treat the word "object" in "where-object" as implying $_; if we agree that the parameter form -Property 'Foo' -oper -Value $bar equals a scriptblock form { $_.Foo -oper $bar }, then it makes sense to allow leaving any of those parts out in the parameter form and have the behaviour the same as if you left them out in the scriptblock form. The following patterns fall out of it, the first two are valid now, the last two are not, but seem fitting:
# param + operator
| where-object { $_.Foo -gt $bar } # scriptblock pattern becomes:
| where-object -Property Foo -gt -Value $bar # parameter form.
| where-object Foo -gt $bar # binding without parameter names.
Import-Csv test.csv | where-object Quantity -gt 5 # example use.
# param only
| where-object { $_.Foo } # casting the property value to bool
| where-object -Property Foo # doing that by leving out -Value param
| where-object Foo # and by positional binding
Import-Csv test.csv | where-object InStock
# Operator only
| where-object { $_ -gt $bar } # no property specified, ->
| where-object -gt $bar # $_ is implied by the "object" part of "Where-Object"
Get-Content test.txt | where-object -match 'baz'
# Neither
| where-object { $_ } # implicitly casting the object to bool
| where-object # $_ is implied by the "object" part of "where-object"
Get-Content test.txt| Where-Object
If we did use _ that also works, but it is a bit of a weird special case, and things seem to work neatly without that.
Reacted by Rain Sallow (/u/ta11ow), Michael Klement, Travis C. LaGrone and Josh Hall
While omission may be slightly more obscure at first, proper documentation should address that.
Similarly, I feel that it should be sufficient to properly document the implicit Boolean logic that Where-Objectalready applies, obviating the need for something like -Truthy.
After all, something like 'hi', '', 'there' | Where-Object Length in lieu of 'hi', '', 'there' | Where-Object Length -gt 0 works fine.
The problem arises with how parameters are defined. If you attempt to do the above with Where-Object -gt 1 you hit an issue — the value 1 is assigned by position, and ends up being assigned to the -Property parameter, not-Value.
I'm considering whether simply dropping -Value as a parameter might be a better option, and having the "value" be taken by the selected operator parameter, rather than have them be switch parameters. This would be a breaking change as it would technically remove an operator, but I think is preferable to having a confusing and potentially unpredictable doubling up on the parameters. (And, at least in the scripts I see, people actually specifying -Value by name are extremely rare.)
The alternative would be doing the above without dropping -Value as a parameter, which means we have to do a runtime check to ensure users don't accidentally provide a value to both parameters.
Either method is fine, but I'd be interested to hear what y'all think of that. 😄
Basically unless we want to do a whole lot of really kludgy implementation special-casing here, the most elegant and effective solution is just to completely drop the -Value parameter and have the -eq and other parameters (which are currently switches) take the value themselves (causing them to be typed object) and snip out the frankly just-getting-in-the-way-at-this-point -Value parameter completely.
This allows the following new syntaxes:
$Array|Where-Object# outputs only truthy inputobjects$Array|Where-Object-gt3# outputs only inputobjects that are numerically greater than 3
As well, of course, as all current syntaxes, except one:
$Array|Where-Object-Property $Name-eq-Value 2
Any existing code instances where -Value is explicitly specified will unfortunately fail; and I don't really see an easy way around that issue. Without doing it like this, the $Array | Where-Object -gt 3 assigns 3 to the -Property parameter by position instead.
Bruce Payette (@BrucePay) I'd appreciate your thoughts on this approach and/or any better alternatives if you are thinking of something I've missed. 😄
Reacted by Michael Klement, HumanEquivalentUnit and Travis C. LaGrone
I too was hoping that eliminating -Value can be considered a Bucket 3: Unlikely Grey Area change, but a quick search tells me that it is being used (I've gone through abut 20 pages' worth, which had many false positives, but I've encountered about a dozen distinct repos that use it).
We can work around that with a bit of a kludge that simulates the presence of a -Value parameter, as in the following PowerShell PoC:
[CmdletBinding()]
param(
# Operator with operand
[object] $GT,# Ideally, we'd hide this parameter from the syntax diagrams# See https://github.com/PowerShell/PowerShell/issues/7868
[Parameter(ValueFromRemainingArguments)]
[object[]] $LegacyRest
)
if ($LegacyRest.Count-gt0) {
if ($LegacyRest.Count-eq1-and$GT-is [string] -and0-eq'-Value'.IndexOf($GT, [StringComparison]::InvariantCultureIgnoreCase)) {
# Direct operand was '-Value' (or an abbreviation), so we expect the true# operand as the one and only element of $LegacyRest.$GT=$LegacyRest[0]
} else { # Unexpected extra arguments.# Should be a *statement*-terminating error.Throw"A parameter cannot be found that accepts '$LegacyRest'."
}
}
# Echo the effective operand."[$GT]"
The above would support foo -GT 3 as well as foo -GT -Value 3.
Caveats:
foo 3 -gt -Value would also work, but I don't think we need to worry about that.
Single-character abbreviation -v for -Value wouldn't work anymore, because in the absence of an actual -Value parameter -v unambiguously binds to -Verbose - again, not something I think we need to worry about.
Tab completion for -Value will go away, but I think that's fine, given that we want to steer users toward the operand syntax.
You're right, it is kind of a kludge. Considering the fact that -Value already exists I'd prefer to just keep it on as a parameter and have it determine which to use based on which is supplied.
Not sure quite how to handle that in the actual code at the moment, though, due to how the parameters interact with the getters and setters.
Running into parameter set issues again, I suppose that's predictable. I'd prefer to break it cleanly with my previous idea, but backwards compat would be a bit annoying to break I suppose. 🤔
Will think on this some more this week/end and see if I can wrangle the parameter sets sensibly. So far that's a bit dicey to do. 🙂
I'm not surprised there's not a simple way to search object property names and values without resorting to findstr. Select-string doesn't have the right effect.
get-process cmd | findstr /i cmd
Sure this works but it still returns all the properties:
get-process cmd |where { $_-match'cmd' }
Here's my first attempt at a "search-object":
# search-object.ps1param ($pattern)
begin {
$hash=@{}
}
process {
$obj=$_$obj|Get-Member|foreach name |foreach {
$name=$_$value=$obj.$nameif ($name-match$pattern-or$value-match$pattern) {
$hash+=@{$name=$value}
}
}
[pscustomobject]$hash
}
jszabo98, this issue is about making object-based filtering via Where-Object easier, not about string searches; changing the currently unintuitive behavior of Select-String is the subject of the enhancement request in #10726.
jszabo98: the description of your intended results does not match with what the example commands are actually doing (suggesting that you perhaps don't "get" the way powershell works). You state that you are trying to search object property names and values but
get-process cmd | findstr /i cmd
simply finds all the lines produced by Get-ProcessAFTER its output objects are converted to text by Format-Table (or maybe Format-List for other cmdlets with more default displayed properties). In this case that's every line except the column headers, since you restricted Get-Process to only produce output objects for processes named "cmd". So no "selection" of property names or values.
In
get-process cmd | where { $_ -match 'cmd' }
you are selecting Get-Process output objects which -match 'cmd' but -match only operates on [String] or [String[]] (i.e. single strings or arrays of string). Thus, every Get-Process output object is first converted to a [String] before the match is attempted. Since the ToString() method of [System.Diagnostics.Process] simply appends the process name to the type name (supplied by [Object].ToString()), $_ gets converted to "System.Diagnostics.Process (cmd)" which then matches so the entire object is passed through Where-Object.
If you had not restricted the output of Get-Process, the result would have been similar except that the output would have included any process that had a name which matched 'cmd' (i.e. if the name had 'cmd' anywhere in it).
In 'search-object.ps1', (ignoring several possible optimizations) you set $hash to an empty hash table in the -Begin script block (executed only once before processing any input objects) and then add each found item in the -Process script block. This means that the hash table will try to accumulate the matched properties of the current object and every preceding object. The most likely result is that you will have two objects match on the values of properties with same name or just have the names match $pattern. Attempting to add an item with the same name as an existing item will throw an exception. You could change $hash += @{$name = $value} to $hash[$name] = $value thus overwriting the value for each new object processed (automatically creating an item if it doesn't exist), however you will still accumulate items from previously processed objects. Unless this is what you intended, you need to place the $hash = @{} at the beginning of the -Process script block to have an empty hash table for each object to be matched (this would also solve the duplicate name problem).
Regarding the problem of accessing the object as a whole instead of a particular property, how about changing the allowed arguments to -Property to include methods? This would allow access to strings and value type objects as follows:
Where-Object 'tostring()' -eq 'cmd' # trying to match a string object
Where-Object 'tostring("x")' -match '00$' # trying to match a numeric value which is a multiple of 256
# not the most efficient way, just a demonstration of the potential versatility available
Where-Object 'toint32($null)' -gt 1024 # checking the value of a numeric or parsed string
# had to use $null since no overload of ToInt32 with 0 arguments
# "properties" are verbatim quoted to prevent parser errors
The main argument in favour of this is that it provides the desired functionality for strings (vast majority of cases) but does not introduce any special cases or break existing syntax. While not as compact as perhaps desired, there might be efficiency benefits to directly calling a method and processing the result within the cmdlet instead of calling a script block to do the work.
That would probably be best served as a completely separate feature request UberKluger 🙂
It would need investigation before making that assumption, though. The ways cmdlets can bind dynamic properties/methods is complicated, and although ForEach-Objectdoes have a parameter that does that kind of thing (-MemberName) if my memory is decently reliable, it often ends up being slower than putting the method call in a scriptblock instead.
Rain Sallow (/u/ta11ow) (@vexx32), you're probably thinking of #7700, though I suspect that there's ultimately no good reason for, say, Get-Item $PROFILE | ForEach-Object ToString to be slower than Get-Item $PROFILE / ForEach-Object { $_.ToString() }.
UberKluger, I see searching string representations of objects as a separate use case and suggest sticking with the object/property scenario for Where-Object.
If there really is a need to call .ToString() with arguments and test against the result, the script-block syntax has that covered (0x100 | Where-Object { $_.ToString("x") -match '00$' })
A related scenario is to have a quick-and-dirty way to search the string representations as they would print to the console (the rich, user-friendly representations provided by the formatting system), line by line.
This should be covered by Select-String, but currently isn't: e.g., you should be able to run Get-Date | Select-String July and get a result (in July, with an English-based culture), but you currently must use Get-Date | Out-String -Stream | Select-String July, i.e. an explicit call to the formatting system, because Select-String currently operates on the typically-useless .ToString() representations - see #10726 (comment)
Where-Object's params providing shorthands for builtin operators, one can skip the scriptblock and write:
Get-ChildItem | Where-Object { $_.Name -match '\.(txt|md)$' }
Activity
jcotton42 commentedon Nov 29, 2018
I like this proposal, but I'm very not sold on just
where-objecttesting for truthiness, feels too crypticHumanEquivalentUnit commentedon Nov 29, 2018
I'm not sold on that part either, but
where { $_ }is pretty cryptic, andwhere -property x -eq $truecasts the wrong way, $true gets cast to string, instead of the property being cast to bool, so that looks like it would work but it "surprisingly" doesn't.The concept "filter things which are truthy" is useful, and it sort of falls out of this request - with a property it maps to
{$_.Prop -op $value}, then with this request if you don't specify-propertyit works on "the object in the pipeline" and maps to{$_ -op $value}, and then if you don't specify the operation either it would map to just{$_}. This part could be separated out into a different request for a way to say something likewhere-object -Truthy.nohwnd commentedon Nov 29, 2018
I would like to say that even though the operators already filter collections without using
where:I am still missing the proposed syntax, because it would allow for using less parentheses. A command followed by a pipeline is not "overloaded", unlike a command followed by an operator. In that case the operator is considered a parameter of the command, and parentheses must be used:
The truthiness I am also not sold at.
BrucePay commentedon Nov 29, 2018
HumanEquivalentUnit The inability to specify the whole object has annoyed me for years. I'd always expected that we would use
-Property _to mean the whole object but that never got implemented. Of course there's no reason not to do it now. Sowould be equivalent to
vexx32 commentedon Nov 29, 2018
That's not a bad idea Bruce Payette (@BrucePay) but it does prevent anyone from making use of a property actually named
_(i.e.,| where {$_._ -gt 5}would be rendered impossible to work with using the parameter syntax).BrucePay commentedon Nov 29, 2018
Rain Sallow (/u/ta11ow) (@vexx32) Practically speaking, the likelihood of a property named '_' is miniscule. And should it occur, you can always use the scriptblock form of the command. After all, the property syntax is a very small subset of what you can do in a scriptblock. Sso I don't see this as a significant concern.
vexx32 commentedon Nov 29, 2018
Certainly, but I don't see why
Where _ -gt 5is better thanWhere-Object -gt 5; arguably the latter is more clear in intent, and doesn't risk being confused for an (admittedly unwise) property name. 😄HumanEquivalentUnit commentedon Nov 29, 2018
Bruce Payette (@BrucePay) I like the use of
_well enough; right now,gci | where lengthfilters on the property Length being truthy, so|where _is a valid instruction. Clashing with properties called_doesn't bother me, but special casing-Property _to mean "the object" feels weird, is there anywhere else that meaning exists? Would people then expect it to work with other cmdlets that have a -Property?What do you think of the idea of it being valid to use where-object with no parameters at all?
It's growing on me to treat the word "object" in "where-object" as implying
$_; if we agree that the parameter form-Property 'Foo' -oper -Value $barequals a scriptblock form{ $_.Foo -oper $bar }, then it makes sense to allow leaving any of those parts out in the parameter form and have the behaviour the same as if you left them out in the scriptblock form. The following patterns fall out of it, the first two are valid now, the last two are not, but seem fitting:If we did use
_that also works, but it is a bit of a weird special case, and things seem to work neatly without that.mklement0 commentedon Nov 29, 2018
Good point re name collisions, Rain Sallow (/u/ta11ow) (@vexx32) and HumanEquivalentUnit; omitting
-Propertyaltogether (... | where -gt 5), as HumanEquivalentUnit suggests, seems like a good solution.While omission may be slightly more obscure at first, proper documentation should address that.
Similarly, I feel that it should be sufficient to properly document the implicit Boolean logic that
Where-Objectalready applies, obviating the need for something like-Truthy.After all, something like
'hi', '', 'there' | Where-Object Lengthin lieu of'hi', '', 'there' | Where-Object Length -gt 0works fine.I've created two doc issues:
Suggestion to create a conceptual topic that explains PowerShell's implicit to-Boolean coercion logic: Introduce a new conceptual topic that explains to-Boolean coercion logic ("truthiness") MicrosoftDocs/PowerShell-Docs#3356
Suggestion to link to that topic from the
Where-Objecttopic and explain how implicit Boolean logic can be leveraged withWhere-Object: Amend the Where-Object topic to explain the implicit Boolean logic that may be applied MicrosoftDocs/PowerShell-Docs#3357vexx32 commentedon Dec 1, 2018
Michael Klement (@mklement0) HumanEquivalentUnit So I rolled some code to try this out, and it sort of works. Well, truthiness does, at least:
The problem arises with how parameters are defined. If you attempt to do the above with
Where-Object -gt 1you hit an issue — the value1is assigned by position, and ends up being assigned to the-Propertyparameter, not-Value.I'm considering whether simply dropping
-Valueas a parameter might be a better option, and having the "value" be taken by the selected operator parameter, rather than have them be switch parameters. This would be a breaking change as it would technically remove an operator, but I think is preferable to having a confusing and potentially unpredictable doubling up on the parameters. (And, at least in the scripts I see, people actually specifying-Valueby name are extremely rare.)The alternative would be doing the above without dropping
-Valueas a parameter, which means we have to do a runtime check to ensure users don't accidentally provide a value to both parameters.Either method is fine, but I'd be interested to hear what y'all think of that. 😄
vexx32 commentedon Dec 2, 2018
HumanEquivalentUnit
Update: Got a properly working implementation over here: https://github.com/vexx32/PowerShell/blob/093ef91fac588bb730a81ad2926166f23e4d08b5/src/System.Management.Automation/engine/InternalCommands.cs#L853
Basically unless we want to do a whole lot of really kludgy implementation special-casing here, the most elegant and effective solution is just to completely drop the
-Valueparameter and have the-eqand other parameters (which are currently switches) take the value themselves (causing them to be typedobject) and snip out the frankly just-getting-in-the-way-at-this-point-Valueparameter completely.This allows the following new syntaxes:
As well, of course, as all current syntaxes, except one:
Any existing code instances where
-Valueis explicitly specified will unfortunately fail; and I don't really see an easy way around that issue. Without doing it like this, the$Array | Where-Object -gt 3assigns3to the-Propertyparameter by position instead.Bruce Payette (@BrucePay) I'd appreciate your thoughts on this approach and/or any better alternatives if you are thinking of something I've missed. 😄
mklement0 commentedon Dec 2, 2018
Well done, Rain Sallow (/u/ta11ow) (@vexx32).
I too was hoping that eliminating
-Valuecan be considered a Bucket 3: Unlikely Grey Area change, but a quick search tells me that it is being used (I've gone through abut 20 pages' worth, which had many false positives, but I've encountered about a dozen distinct repos that use it).We can work around that with a bit of a kludge that simulates the presence of a
-Valueparameter, as in the following PowerShell PoC:The above would support
foo -GT 3as well asfoo -GT -Value 3.Caveats:
foo 3 -gt -Valuewould also work, but I don't think we need to worry about that.Single-character abbreviation
-vfor-Valuewouldn't work anymore, because in the absence of an actual-Valueparameter-vunambiguously binds to-Verbose- again, not something I think we need to worry about.Tab completion for
-Valuewill go away, but I think that's fine, given that we want to steer users toward the operand syntax.As suggested in Can we hide obsolete or internal-use-only helper parameters from syntax diagrams? #7868, it would be nice to be able to hide obsolete parameter or, as in this case, helper parameters that solely exist to preserve backward compatibility.
vexx32 commentedon Dec 2, 2018
Hmm, with a ValueFromRemainingArguments...
You're right, it is kind of a kludge. Considering the fact that
-Valuealready exists I'd prefer to just keep it on as a parameter and have it determine which to use based on which is supplied.Not sure quite how to handle that in the actual code at the moment, though, due to how the parameters interact with the getters and setters.
5 remaining items
rkeithhill commentedon Nov 19, 2019
I'd love to see this functionality!!
vexx32 commentedon Nov 19, 2019
Running into parameter set issues again, I suppose that's predictable. I'd prefer to break it cleanly with my previous idea, but backwards compat would be a bit annoying to break I suppose. 🤔
Will think on this some more this week/end and see if I can wrangle the parameter sets sensibly. So far that's a bit dicey to do. 🙂
jszabo98 commentedon Feb 4, 2020
I'm not surprised there's not a simple way to search object property names and values without resorting to findstr. Select-string doesn't have the right effect.
Sure this works but it still returns all the properties:
Here's my first attempt at a "search-object":
Modules : {System.Diagnostics.ProcessModule (cmd.exe), System.Diagnostics.ProcessModule (ntdll.dll), System.Diagnostics.ProcessModule (KERNEL32.DLL), System.Diagnostics.ProcessModule (KERNELBASE.dll)...} Path : C:\Windows\System32\cmd.exe MainModule : System.Diagnostics.ProcessModule (cmd.exe) ProcessName : cmd Name : cmd MainWindowTitle : cmd - powershellmklement0 commentedon Feb 4, 2020
jszabo98, this issue is about making object-based filtering via
Where-Objecteasier, not about string searches; changing the currently unintuitive behavior ofSelect-Stringis the subject of the enhancement request in #10726.UberKluger commentedon Jul 5, 2020
jszabo98: the description of your intended results does not match with what the example commands are actually doing (suggesting that you perhaps don't "get" the way powershell works). You state that you are trying to search object property names and values but
simply finds all the lines produced by
Get-ProcessAFTER its output objects are converted to text byFormat-Table(or maybeFormat-Listfor other cmdlets with more default displayed properties). In this case that's every line except the column headers, since you restrictedGet-Processto only produce output objects for processes named "cmd". So no "selection" of property names or values.In
you are selecting
Get-Processoutput objects which-match'cmd' but-matchonly operates on[String]or[String[]](i.e. single strings or arrays of string). Thus, everyGet-Processoutput object is first converted to a[String]before the match is attempted. Since theToString()method of[System.Diagnostics.Process]simply appends the process name to the type name (supplied by[Object].ToString()),$_gets converted to "System.Diagnostics.Process (cmd)" which then matches so the entire object is passed throughWhere-Object.If you had not restricted the output of
Get-Process, the result would have been similar except that the output would have included any process that had a name which matched 'cmd' (i.e. if the name had 'cmd' anywhere in it).In 'search-object.ps1', (ignoring several possible optimizations) you set
$hashto an empty hash table in the-Beginscript block (executed only once before processing any input objects) and then add each found item in the-Processscript block. This means that the hash table will try to accumulate the matched properties of the current object and every preceding object. The most likely result is that you will have two objects match on the values of properties with same name or just have the names match$pattern. Attempting to add an item with the same name as an existing item will throw an exception. You could change$hash += @{$name = $value}to$hash[$name] = $valuethus overwriting the value for each new object processed (automatically creating an item if it doesn't exist), however you will still accumulate items from previously processed objects. Unless this is what you intended, you need to place the$hash = @{}at the beginning of the-Processscript block to have an empty hash table for each object to be matched (this would also solve the duplicate name problem).UberKluger commentedon Jul 5, 2020
Regarding the problem of accessing the object as a whole instead of a particular property, how about changing the allowed arguments to
-Propertyto include methods? This would allow access to strings and value type objects as follows:The main argument in favour of this is that it provides the desired functionality for strings (vast majority of cases) but does not introduce any special cases or break existing syntax. While not as compact as perhaps desired, there might be efficiency benefits to directly calling a method and processing the result within the cmdlet instead of calling a script block to do the work.
vexx32 commentedon Jul 5, 2020
That would probably be best served as a completely separate feature request UberKluger 🙂
It would need investigation before making that assumption, though. The ways cmdlets can bind dynamic properties/methods is complicated, and although
ForEach-Objectdoes have a parameter that does that kind of thing (-MemberName) if my memory is decently reliable, it often ends up being slower than putting the method call in a scriptblock instead.mklement0 commentedon Jul 5, 2020
Rain Sallow (/u/ta11ow) (@vexx32), you're probably thinking of #7700, though I suspect that there's ultimately no good reason for, say,
Get-Item $PROFILE | ForEach-Object ToStringto be slower thanGet-Item $PROFILE / ForEach-Object { $_.ToString() }.UberKluger, I see searching string representations of objects as a separate use case and suggest sticking with the object/property scenario for
Where-Object.If there really is a need to call
.ToString()with arguments and test against the result, the script-block syntax has that covered (0x100 | Where-Object { $_.ToString("x") -match '00$' })A related scenario is to have a quick-and-dirty way to search the string representations as they would print to the console (the rich, user-friendly representations provided by the formatting system), line by line.
This should be covered by
Select-String, but currently isn't: e.g., you should be able to runGet-Date | Select-String Julyand get a result (in July, with an English-based culture), but you currently must useGet-Date | Out-String -Stream | Select-String July, i.e. an explicit call to the formatting system, becauseSelect-Stringcurrently operates on the typically-useless.ToString()representations - see #10726 (comment)microsoft-github-policy-service commentedon Nov 23, 2023
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.
dkaszews commentedon Apr 23, 2025
Bump from https://stackoverflow.com/questions/79588233/apply-where-object-shorthand-operators-to-entire-object/79588561#79588561