如何在第一次匹配时停止管道过滤(Where-Object)

E23*_*235 5 powershell pipeline break

我搜索过但还没有找到如何做。
我正在研究从大文件(~2GB)中过滤数据。
我使用过Where-Object,当它找到匹配时,它会继续搜索其他有意义的匹配。

有可能在第一场比赛就停止吗?

例如(#1)

Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")}
Run Code Online (Sandbox Code Playgroud)

输出将是:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    666      38    26928      18672    92             568 svchost
    596      28    11516      16560    92             792 svchost
    425      14     5364       7036    45             832 svchost
    406      17     7032       8416    39            1004 svchost
Run Code Online (Sandbox Code Playgroud)

我想要的是在第一场比赛后返回输出:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    666      38    26928      18672    92             568 svchost
Run Code Online (Sandbox Code Playgroud)

这是我尝试过的(也使用 Foreach-Object):

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){return $_}}
Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){return $_;break;}}    
Get-Process | ForEach-Object {if($_.ProcessName.StartsWith("svchost")){return $_}}
Run Code Online (Sandbox Code Playgroud)

但它仍然返回完整的输出。
参考:
如何在Powershell中打破Foreach循环?
是否可以从过滤器内终止或停止 PowerShell 管道

编辑(关于大数据问题的解释):
示例(#2):
我有两个 XML:
A.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Events>
  <Event>
    <EventData Name="Time">09/10/2017 12:54:16</EventData>
    <EventData Name="WorkstationName">USER2-PC</EventData>
    <EventData Name="UserName">user2</EventData>
  </Event>  
</Events>
Run Code Online (Sandbox Code Playgroud)

B.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Events>
   <Event>
    <EventData Name="Time">09/10/2017 14:54:16</EventData>
    <EventData Name="WorkstationName">USER1-PC</EventData>
    <EventData Name="UserName">user1</EventData>
  </Event>
  <Event>
    <EventData Name="Time">09/10/2017 13:54:16</EventData>
    <EventData Name="WorkstationName">USER2-PC</EventData>
    <EventData Name="UserName">user2</EventData>
  </Event> 
 ... (more 100,000 events like the above two)
</Events>
Run Code Online (Sandbox Code Playgroud)

这些 XML 将作为对象加载:

$fileA = "C:\tmp\A.xml"
$a = New-Object Xml.XmlDocument
$a.Load($fileA)

$fileB = "C:\tmp\B.xml"
$b = New-Object Xml.XmlDocument
$b.Load($fileB)
Run Code Online (Sandbox Code Playgroud)

然后我想搜索相同用户名的第一个匹配项:

$result = $b.Events.Event | Where-Object {
    (($_.EventData | where-object {$_.Name -eq "UserName"})."#text" -eq $username)
}

$result.EventData
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果我在第一个事件上有匹配项,那么运行其余 99,999 个事件就是浪费时间。

编辑(已解决):
阅读尼克的回答后,我没有尝试过任何新内容。
命令:

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){ $_;break;}}  
Run Code Online (Sandbox Code Playgroud)

确实停止了,Where-Object但它不返回该项目。
这个问题可以通过以下方法解决:

Get-Process | Where-Object {if($_.ProcessName.StartsWith("svchost")){ $someVar = $_;break;}}  
Run Code Online (Sandbox Code Playgroud)

因此我标记了他的答案。

Nic*_*ick 5

如果您需要效率,您可以尝试将其分解为循环:

Get-Process | foreach {If ($_.ProcessName.StartsWith("svchost")){$_;break}}
Run Code Online (Sandbox Code Playgroud)

您可以通过此检查确认它是否有效:

$i=0; Get-Process | foreach {$i++;$i; If ($_.ProcessName.StartsWith("svchost")){$_;break}}
Run Code Online (Sandbox Code Playgroud)

它将使循环在每次循环时打印出一个数字,在我的例子中,它达到了 115,然后如果我(Get-Process).Count157进程,那么它会循环遍历我的进程,找到我们想要的进程,然后停止循环。

正如其他答案中所述,您可以使用[0],在任何数组或列表上,您可以使用方括号内的索引选择单个行,但要小心,因为在 null 或空对象上尝试这样做会引发异常:

(Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")})[0]
Run Code Online (Sandbox Code Playgroud)

或者你可以Select-Object以类似的方式工作,但有比索引更多的选项,并且如果对象为 null 或空,则不会抛出任何错误。

Get-Process | Where-Object {$_.ProcessName.StartsWith("svchost")} | Select-Object -First 1
Run Code Online (Sandbox Code Playgroud)

然而,在您选择第一个结果之前,这两个选项仍然会评估整个列表。