Reputation: 3193
Is there any way of getting the intrinsic numeric index (order#)
of the selected/filtered/matched object
from a Where-Object processing?
for example:
Get-Process | Where-Object -property id -eq 1024
without using further code...
?is it possible to get the index of the object with ID=4
from some 'inner/hidden' Powershell mechanism???
or instruct Where-Object to spit out the index
where the match(es) took place?
(in this case would be 1, 0 is the 'idle' process)
Upvotes: 2
Views: 708
Reputation: 27516
Or something like this. Add a property called line that keeps increasing for each object.
ps | % { $line = 1 } { $_ | add-member line ($line++) -PassThru } | where id -eq 13924 |
select line,id
line Id
---- --
184 13924
Upvotes: 0
Reputation: 439487
No, there is no built-in mechanism for what you're looking for as of PowerShell 7.1
If only one item is to be matched - as in your case - you can use the Array
type's static .FindIndex()
method:
$processes = Get-Process
# Find the 0-based index of the process with ID 1024.
[Array]::FindIndex($processes, [Predicate[object]] { param($o) $o.Id -eq 1024 })
Note that this returns a zero-based index if a match is found, and -1
otherwise.
The ::FindIndex()
method has the advantage of searching only for the first match, unlike Where-Object
, which as of PowerShell 7.1 always searches the entire input collection (see below). As a method rather than a pipeline-based cmdlet, it invariably requires the input array to be in memory in full (which the pipeline doesn't require).
While it wouldn't directly address your use case, note that there's conceptually related feature request #13772 on GitHub, which proposes introducing an automatic $PSIndex
variable to be made available inside ForEach-Object
and Where-Object
script blocks.
As an aside:
Note that while [Array]::FindIndex
only ever finds the first match's index, Where-Object
is limited in the opposite way: as of PowerShell 7.1, it always finds all matches, which is inefficient if you're only looking for one match.
While the related .Where()
array method does offer a way to stop processing after the first match (e.g.,
('long', 'foo', 'bar').Where({ $_.Length -eq 3 }, 'First')
), methods operate on in-memory collections only, so it would be helpful if the pipeline-based Where-Object
cmdlet supported such a feature as well - see GitHub feature request #13834.
Upvotes: 2
Reputation: 61178
You could capture the result of the Get-Process
cmdlet as array, and use the IndexOf()
method to get the index or -1 if that Id is not found:
$gp = (Get-Process).Id
$gp.IndexOf(1024)
Upvotes: 1