news 2026/5/2 7:58:24

PowerShell 第11章:过滤和比较(下)Where-Object、迭代命令行模型、$_作用域与实战练习

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PowerShell 第11章:过滤和比较(下)Where-Object、迭代命令行模型、$_作用域与实战练习

🔥个人主页:杨利杰YJlio
❄️个人专栏:《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》
《微信助手》 《锤子助手》 《Python》 《Kali Linux》
《那些年未解决的Windows疑难杂症》
🌟让复杂的事情更简单,让重复的工作自动化


PowerShell 第11章:过滤和比较(下)Where-Object、迭代命令行模型、$_作用域与实战练习

  • 1. 写在前面:从“会比较”到“会过滤”
  • 2. Where-Object:PowerShell 的万能过滤器
    • 2.1 标准语法:推荐优先掌握
    • 2.2 `$_` 表示当前对象
    • 2.3 Where-Object 的工作原理
  • 3. Where-Object 的标准写法、简写与多条件过滤
    • 3.1 标准写法
    • 3.2 v3 简写写法
    • 3.3 多条件过滤示例
    • 3.4 典型布尔逻辑示例
  • 4. PSICLM:迭代命令行模型,把复杂需求拆成 5 步
    • 4.1 示例需求
    • 4.2 第一步:先获取进程
    • 4.3 第二步:排除 PowerShell 本体
    • 4.4 第三步:按 VM 降序排序
    • 4.5 第四步:只取前 10 个
    • 4.6 第五步:统计 VM 总和
  • 5. `$_` 到底什么时候能用?
    • 5.1 正确示例:Where-Object 中使用
    • 5.2 正确示例:ForEach-Object 中使用
    • 5.3 错误思路:把 `$_` 当成全局变量
    • 5.4 括号子管道中的 `$_` 作用域
    • 5.5 一张表看懂 `$_` 作用域
  • 6. 远程与性能意识:把过滤推到数据源
    • 6.1 优先级:-Filter > Where-Object
    • 6.2 远程场景不要本地拉海量数据
    • 6.3 常见场景建议
  • 7. 常见坑位与规避方法
    • 7.1 坑位一:把 Where-Object 当第一选择
    • 7.2 坑位二:混淆列头名和属性名
    • 7.3 坑位三:在不支持的上下文使用 `$_`
    • 7.4 坑位四:括号子管道作用域没分清
    • 7.5 坑位五:忽略远程性能
  • 8. 经典实战清单:带答案思路
    • 8.1 查看物理网卡列表
    • 8.2 查看 DNS 缓存中的 A / AAAA 记录
    • 8.3 查找 System32 下大于 5MB 的 EXE 文件
    • 8.4 只列出“安全更新”的补丁
    • 8.5 查找 Conhost 或 Svchost 且运行中的进程
  • 9. 快速对照卡:过滤与比较(下)
    • 9.1 核心口诀
    • 9.2 一张流程图判断该怎么过滤
    • 9.3 推荐命令结构
  • 10. 我的理解:Where-Object 是过滤器,不是万能第一步
  • 11. 总结:过滤越靠左,命令越稳
  • 参考资料

1. 写在前面:从“会比较”到“会过滤”

在上一篇文章中,我们重点学习了 PowerShell 的左过滤思维和常用比较运算符,例如:

-eq-ne-gt-lt-like-match-and-or-not

这些运算符本身并不复杂,真正难的是把它们放进实际管道中,用来筛选服务、进程、文件、补丁、网卡、DNS 缓存等对象。

这一篇继续 PowerShell 第 11 章“过滤和比较”的下半部分,重点解决四个问题:

  • Where-Object 怎么写才规范?
  • 复杂命令如何一步一步构建?
  • $_到底什么时候能用?
  • 过滤时如何兼顾远程性能和可维护性?

如果说比较运算符是“判断条件”,那么 Where-Object 就是把这些条件真正嵌入 PowerShell 管道的万能过滤器。

这张图可以作为本文的总览。
本文会围绕Where-Object、PSICLM 迭代命令行模型、$_作用域、远程性能意识、常见坑位和实战清单展开。


2. Where-Object:PowerShell 的万能过滤器

Where-Object是 PowerShell 中最常用的过滤命令之一。

它的作用很简单:

让每一个管道对象都经过一段判断逻辑,条件为 True 就保留,条件为 False 就丢弃。

最典型的写法如下:

Get-Service|Where-Object{$_.Status-eq'Running'}

这条命令的意思是:

获取所有服务 ↓ 逐个检查服务对象 ↓ 如果当前服务的 Status 等于 Running ↓ 保留这个服务对象

2.1 标准语法:推荐优先掌握

我更推荐初学者优先记住完整标准写法:

命令|Where-Object{条件表达式}

例如:

Get-Service|Where-Object{$_.Status-eq'Running'}

这里有两个关键点:

部分含义
$_当前正在处理的管道对象
{ }过滤脚本块,返回$true$false

标准语法虽然比简写长一点,但可读性最好,也最适合写进脚本、笔记和企业内部 SOP。

2.2$_表示当前对象

例如:

Get-Service|Where-Object{$_.Status-eq'Running'}

在这条命令中,$_每次代表一个服务对象。

可以理解成:

第 1 次:$_ = 第一个服务 第 2 次:$_ = 第二个服务 第 3 次:$_ = 第三个服务 ……

每个对象都会执行一次{ $_.Status -eq 'Running' }

如果结果为:

$true

这个对象会继续留在管道中。

如果结果为:

$false

这个对象就会被过滤掉。

2.3 Where-Object 的工作原理

上图很好地解释了 Where-Object 的处理过程:

  1. 管道输入多个对象;
  2. Where-Object 逐个检查对象;
  3. 脚本块返回 True / False;
  4. True 的对象保留;
  5. False 的对象丢弃。

Where-Object 不是一次性判断全部对象,而是逐个对象执行过滤条件。


3. Where-Object 的标准写法、简写与多条件过滤

3.1 标准写法

推荐写法:

Get-Service|Where-Object{$_.Status-eq'Running'}

这类写法适合:

  • 单条件过滤;
  • 多条件过滤;
  • 脚本中长期使用;
  • 后续扩展逻辑;
  • 给同事交接命令。

3.2 v3 简写写法

PowerShell v3 之后支持简写:

Get-Service|Where Status-eq'Running'

这条命令和下面写法类似:

Get-Service|Where-Object{$_.Status-eq'Running'}

简写适合临时命令行输入,但我不建议在复杂脚本中大量使用。

原因是:

  • 多条件时可读性下降;
  • 不利于初学者理解$_
  • 复杂表达式容易写乱;
  • 不适合写成培训文档或 SOP。

简写可以会,但标准写法必须熟。

3.3 多条件过滤示例

例如:筛选正在运行且启动类型为手动的服务。

Get-Service|Where-Object{$_.Status-eq'Running'-and$_.StartType-eq'Manual'}

这里使用了:

-and

表示两个条件都必须成立。

也可以写成更清晰的多行版本:

Get-Service|Where-Object{($_.Status-eq'Running')-and($_.StartType-eq'Manual')}

当条件变复杂时,建议使用括号增强可读性。以后回头排查脚本时,会非常省时间。

3.4 典型布尔逻辑示例

筛选名称为conhostsvchost,并且仍在响应的进程:

Get-Process|Where-Object{$_.Name-in@('conhost','svchost')-and$_.Responding}

这里的逻辑是:

  • 名称在conhostsvchost之中;
  • 同时进程处于响应状态。

-in很适合判断“某个值是否在一个集合里”。


4. PSICLM:迭代命令行模型,把复杂需求拆成 5 步

很多人写 PowerShell 命令时,最大的问题不是不会某个命令,而是喜欢一次性写完终极命令。

结果就是:

  • 一写就错;
  • 错了不知道是哪一段错;
  • 输出不符合预期;
  • 只能靠猜改命令。

更稳的方法是使用PSICLM:PowerShell Iterative Command-Line Model,迭代命令行模型

它的核心思想是:

不要一次写完复杂命令,而是先跑通最小子问题,再逐步叠加。

4.1 示例需求

需求:

统计除 PowerShell 进程外,虚拟内存 VM 占用最高的 10 个进程的 VM 总和。

如果直接写最终命令,很容易出错。

更推荐拆成 5 步。

4.2 第一步:先获取进程

Get-Process

先确认你拿到的是进程对象。

可以进一步查看属性:

Get-Process|Get-Member

4.3 第二步:排除 PowerShell 本体

Get-Process|Where-Object{$_.Name-notlike'powershell*'}

这里先过滤掉 PowerShell 相关进程,避免统计时把当前操作环境也算进去。

4.4 第三步:按 VM 降序排序

Get-Process|Where-Object{$_.Name-notlike'powershell*'}|Sort-ObjectVM-Descending

Sort-Object VM -Descending表示按 VM 从高到低排序。

4.5 第四步:只取前 10 个

Get-Process|Where-Object{$_.Name-notlike'powershell*'}|Sort-ObjectVM-Descending|Select-Object-First 10

这一步可以先看 Top 10 是否符合预期。

4.6 第五步:统计 VM 总和

Get-Process|Where-Object{$_.Name-notlike'powershell*'}|Sort-ObjectVM-Descending|Select-Object-First 10|Measure-Object-Property VM-Sum

完整命令最终形成。

这张图适合放在迭代模型章节中。
它把复杂需求拆成了取数据、过滤、排序、取 Top N、统计五个步骤,非常适合 PowerShell 初学者建立正确命令构建方式。

我的建议是:复杂命令不要一次写完,每一步都看输出,确认正确后再叠加下一步。


5.$_到底什么时候能用?

$_是 PowerShell 学习中非常重要、也非常容易混淆的一个符号。

简单来说:

$_只能在支持脚本块处理当前对象的上下文中使用。

常见可用场景包括:

  • Where-Object { }
  • ForEach-Object { }
  • Sort-Object { }
  • Select-Object的计算属性表达式中

5.1 正确示例:Where-Object 中使用

Get-Service|Where-Object{$_.Status-eq'Running'}

这里$_表示当前正在检查的服务对象。

5.2 正确示例:ForEach-Object 中使用

Get-Process|ForEach-Object{$_.Name}

这里$_表示当前进程对象。

5.3 错误思路:把$_当成全局变量

$_不是一个随便哪里都能用的全局变量。

例如:

$name=$_.Name

如果这条命令不在脚本块上下文中,就会出问题。

$_不是“永远代表某个对象”,它只在特定脚本块上下文中代表当前对象。

5.4 括号子管道中的$_作用域

看下面这条命令:

Get-Service-ComputerName(Get-Content.\names.txt|Where-Object{$_-notlike'*dc'})|Where-Object{$_.Status-eq'Running'}

这里有两个$_,但它们不是同一个含义。

第一个$_

Where-Object{$_-notlike'*dc'}

表示Get-Content .\names.txt读出来的每一行字符串,也就是计算机名。

第二个$_

Where-Object{$_.Status-eq'Running'}

表示Get-Service返回的服务对象。

5.5 一张表看懂$_作用域

位置$_代表什么
`Get-Content …Where-Object { $_ }`
`Get-ServiceWhere-Object { $_ }`
`Get-ProcessForEach-Object { $_ }`
Select-Object @{n='X';e={$_.Name}}当前输入对象
普通命令行直接写$_通常无意义或报错

判断$_含义的关键,不是看它长什么样,而是看它前面的管道输入对象是什么。


6. 远程与性能意识:把过滤推到数据源

上一篇讲过“左过滤”,这一篇仍然要强调:Where-Object 很强,但它不一定应该成为第一选择。

6.1 优先级:-Filter > Where-Object

推荐顺序是:

能用原生命令参数过滤 ↓ 就不要先全量取回对象 ↓ 不能参数过滤时 ↓ 再使用 Where-Object

例如 AD 查询:

Get-ADComputer-Filter"Name -like 'DC*'"

优于:

Get-ADComputer-Filter*|Where-Object{$_.Name-like'DC*'}

原因很简单:

  • 前者在 AD 查询阶段就过滤;
  • 后者先把全部对象取回来,再本地过滤;
  • 在对象数量大时,后者更慢,也更消耗资源。

6.2 远程场景不要本地拉海量数据

例如远程查询进程时,不建议先把远程全部数据取回来再筛。

更好的思路是:

  • 能在远端过滤,就在远端过滤;
  • 能用目标命令的过滤参数,就先用参数;
  • 需要远程执行时,用远程会话或对应模块在目标端执行筛选逻辑。

跨网络查询时,本地过滤可能意味着你已经把大量无用对象传回来了。

6.3 常见场景建议

场景推荐做法
AD 查询优先用-Filter
文件筛选优先用-Filter或路径通配
服务名称筛选优先用Get-Service -Name
服务状态筛选使用Where-Object
进程名称筛选优先用Get-Process -Name
复杂多条件筛选Where-Object更灵活
远程海量数据尽量推到远端过滤

Where-Object 是万能过滤器,但不是性能最优过滤器。


7. 常见坑位与规避方法

Where-Object 看起来简单,但实际使用中有几个非常高频的坑。

这张图总结了 Where-Object 使用中最容易踩的 5 个坑:
包括把 Where-Object 当第一选择、混淆列头名与属性名、在错误上下文使用$_、括号子管道作用域没分清、忽略远程性能。

7.1 坑位一:把 Where-Object 当第一选择

错误思路:

Get-ADComputer-Filter*|Where-Object{$_.Name-like'DC*'}

推荐:

Get-ADComputer-Filter"Name -like 'DC*'"

能靠数据源过滤,就先靠数据源过滤。

7.2 坑位二:混淆列头名和属性名

例如Get-Process默认显示里可能有:

PM(K) WS(K) CPU(s)

但这些不一定就是属性名。

如果你直接写:

Get-Process|Where-Object{$_.'PM(K)'-gt10000}

大概率不符合预期。

应该先查看真实属性:

Get-Process|Get-Member

或者:

Get-Process|Select-Object-First 1-Property*

屏幕列头是格式化视图,真实属性要以 Get-Member 为准。

7.3 坑位三:在不支持的上下文使用$_

$_只在脚本块里代表当前对象。

正确:

Get-Service|Where-Object{$_.Status-eq'Running'}

错误:

$ServiceName=$_.Name

如果外面没有管道脚本块,$_就没有明确的当前对象来源。

7.4 坑位四:括号子管道作用域没分清

例如:

Get-Service-ComputerName(Get-Content.\names.txt|Where-Object{$_-notlike'*dc'})|Where-Object{$_.Status-eq'Running'}

两个$_的含义不同:

  • 括号内部的$_是字符串;
  • 括号外部的$_是服务对象。

遇到多层管道时,一定要先问:当前$_到底是哪一种对象?

7.5 坑位五:忽略远程性能

不推荐:

远程取回大量对象|Where-Object{本地过滤}

推荐思路:

尽量在远端过滤 尽量使用目标命令自带过滤参数 尽量减少跨网络传输对象数量

8. 经典实战清单:带答案思路

下面这些练习非常适合用来巩固本章内容。

8.1 查看物理网卡列表

适用 Windows 8 / Windows Server 2012 及以上:

Import-ModuleNetAdapterGet-NetAdapter-Physical

说明:

  • Import-Module NetAdapter加载网卡管理模块;
  • Get-NetAdapter -Physical只显示物理网卡。

8.2 查看 DNS 缓存中的 A / AAAA 记录

Import-ModuleDnsClientGet-DnsClientCache-TypeA,AAAA

说明:

  • A表示 IPv4 记录;
  • AAAA表示 IPv6 记录;
  • -Type是命令自带过滤参数,优先使用。

8.3 查找 System32 下大于 5MB 的 EXE 文件

Get-ChildItemC:\Windows\System32\*.exe|Where-Object{$_.Length-gt5MB}

这里Length是文件对象的大小属性。

也可以进一步展示需要的列:

Get-ChildItemC:\Windows\System32\*.exe|Where-Object{$_.Length-gt5MB}|Select-ObjectName,Length,FullName

8.4 只列出“安全更新”的补丁

Get-HotFix-Description'Security Update'

这里不需要Where-Object,因为Get-HotFix已经提供了-Description参数。

这就是“能参数过滤就不要 Where”的典型例子。

8.5 查找 Conhost 或 Svchost 且运行中的进程

方式一:先用名称过滤,再判断响应状态:

Get-Process-Name conhost,svchost|Where-Object{$_.Responding}

方式二:完全使用 Where-Object:

Get-Process|Where-Object{$_.Name-in@('conhost','svchost')-and$_.Responding}

更推荐第一种,因为它更符合左过滤思维。


9. 快速对照卡:过滤与比较(下)

这张图可以放在文章末尾作为收藏图。
它把本文的核心原则压缩成了一页:优先过滤、靠左过滤、用 Where-Object 处理复杂逻辑、注意$_作用域、使用 Get-Member 查真实属性。

9.1 核心口诀

优先:-Filter > Where-Object 位置:过滤越靠左越好 匹配:-like 用通配符,-match 用正则 大小写:默认不敏感,敏感用 -c* 布尔:-and / -or / -not 属性名:不信列头名,信 Get-Member

9.2 一张流程图判断该怎么过滤

没有

需要

不需要

需要筛选对象

Cmdlet 是否有过滤参数

优先使用过滤参数

使用 Where-Object

是否还需要复杂条件

继续接 Where-Object

进入 Select / Sort / Export

9.3 推荐命令结构

数据源命令|Where-Object{条件}|Select-Object需要的属性|Sort-Object排序属性|Export-Csv输出文件

实际示例:

Get-Service|Where-Object{$_.Status-eq'Running'}|Select-ObjectName,DisplayName,Status|Sort-ObjectName|Export-Csv.\RunningServices.csv-NoTypeInformation-Encoding UTF8

10. 我的理解:Where-Object 是过滤器,不是万能第一步

学完这一章后,我对 Where-Object 的理解是:

Where-Object 很强,但它应该是“必要时使用”,而不是“默认第一选择”。

在日常 Windows 运维中,我们经常会写类似命令:

Get-Service|Where-Object{$_.Status-eq'Running'}

这没有问题,因为Get-Service没有直接按Status过滤的参数。

但如果命令本身已经支持过滤,例如:

Get-Process-Name notepadGet-Service-Name's*'Get-HotFix-Description'Security Update'Get-ADComputer-Filter"Name -like 'DC*'"

那就应该优先使用这些原生过滤能力。

PowerShell 写得好不好,不只看命令能不能跑,还要看它是否少取无关数据、是否容易维护、是否方便排错。

对企业桌面运维来说,这个思路尤其重要。

比如:

  • 查询远程服务;
  • 批量检查补丁;
  • 筛选域内计算机;
  • 扫描大目录文件;
  • 汇总日志或故障对象。

这些场景一旦数据量变大,过滤位置就会直接影响速度和稳定性。

真正成熟的 PowerShell 使用习惯是:先让数据源少吐数据,再让管道精细处理数据。


11. 总结:过滤越靠左,命令越稳

这篇文章围绕 PowerShell 第 11 章“过滤和比较(下)”,重点整理了以下内容:

  1. Where-Object 是 PowerShell 的万能过滤器。
  2. 标准语法Where-Object { $_.属性 -运算符 值 }最值得掌握。
  3. $_表示当前管道对象,但只在支持脚本块的上下文中有效。
  4. v3 简写可以了解,但复杂条件建议使用标准写法。
  5. 复杂命令不要一次写完,应使用 PSICLM 迭代命令行模型逐步构建。
  6. 括号子管道里的$_和外层$_不是同一个作用域。
  7. 远程和大数据量场景下,要尽量把过滤推到数据源。
  8. 不要混淆屏幕列头和真实属性名,真实属性以Get-Member为准。
  9. 能用命令参数过滤,就不要先全量取回再 Where-Object。
  10. 过滤越靠左,传输越少,计算越轻,命令越稳。

Where-Object 不是错,错的是在可以左过滤的场景里,把所有对象先拉回来再过滤。

推荐做法是:先参数过滤,再 Where-Object,最后 Select、Sort、Export。

这套思维掌握后,后续学习批量处理、远程管理、日志分析和自动化巡检都会更顺。

最后用一句话总结:

PowerShell 过滤不是只会 Where-Object,而是知道什么时候不用 Where-Object。


参考资料

  • PowerShell 官方帮助系统
  • Get-Help Where-Object
  • Get-Help about_Comparison_Operators
  • Get-Help about_Logical_Operators
  • Get-Help Get-Service
  • Get-Help Get-Process
  • Get-Help Get-ChildItem
  • Get-Help Measure-Object
  • Get-Help Sort-Object
  • Get-Help Select-Object

🔝 返回顶部

点击回到顶部

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 7:48:23

iphone-inline-video快速上手:5分钟实现iOS视频内联播放

iphone-inline-video快速上手:5分钟实现iOS视频内联播放 【免费下载链接】iphone-inline-video 📱 Make videos playable inline on the iPhone (prevents automatic fullscreen) 项目地址: https://gitcode.com/gh_mirrors/ip/iphone-inline-video …

作者头像 李华
网站建设 2026/5/2 7:46:07

ComfyUI-Easy-Use实战教程:从简单提示到复杂工作流

ComfyUI-Easy-Use实战教程:从简单提示到复杂工作流 【免费下载链接】ComfyUI-Easy-Use In order to make it easier to use the ComfyUI, I have made some optimizations and integrations to some commonly used nodes. 项目地址: https://gitcode.com/gh_mirro…

作者头像 李华
网站建设 2026/5/2 7:45:24

CSS如何让SVG图标适应文字颜色_使用fill属性设置为currentColor

SVG图标不随文字变色是因为fill被内联属性强制锁定&#xff0c;需清除所有内联fill/stroke、内联SVG、为path等元素显式设fill: currentColor&#xff0c;并确保父元素定义color值。SVG图标不随文字变色&#xff1f;检查fill是否被内联覆盖直接写在<svg>标签里的fill属性…

作者头像 李华
网站建设 2026/5/2 7:43:26

Portable Hermes Agent:零门槛AI智能体桌面应用部署与实战

1. 项目概述&#xff1a;一个开箱即用的全能AI智能体桌面应用 如果你和我一样&#xff0c;对AI智能体&#xff08;AI Agent&#xff09;充满好奇&#xff0c;但又对复杂的命令行、Docker容器和系统权限望而却步&#xff0c;那么今天分享的这个项目&#xff0c;绝对会让你眼前一…

作者头像 李华
网站建设 2026/5/2 7:39:26

从编程思维看离散数学:Python如何帮你自动判断命题公式类型?

从编程思维看离散数学&#xff1a;Python如何帮你自动判断命题公式类型&#xff1f; 离散数学作为计算机科学的基石&#xff0c;其核心概念如命题逻辑、真值表和范式在算法设计、电路优化等领域无处不在。但传统教学中&#xff0c;学生往往需要手动绘制复杂的真值表&#xff0c…

作者头像 李华
网站建设 2026/5/2 7:34:41

超宽带天线设计原理与工程实践

1. 超宽带天线设计基础与核心挑战在无线通信技术快速发展的今天&#xff0c;超宽带(UWB)天线因其独特的工作机制和性能特点&#xff0c;正在雷达探测、精确定位和高速数据传输等领域展现出不可替代的价值。与传统窄带天线不同&#xff0c;UWB天线需要在极宽的频率范围内&#x…

作者头像 李华