PowerShell 第11章:过滤和比较(下)Where-Object、迭代命令行模型、$_作用域与实战练习
个人主页杨利杰YJlio❄️个人专栏《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》《微信助手》 《锤子助手》 《Python》 《Kali Linux》《那些年未解决的Windows疑难杂症》让复杂的事情更简单让重复的工作自动化PowerShell 第11章过滤和比较下Where-Object、迭代命令行模型、$_作用域与实战练习1. 写在前面从“会比较”到“会过滤”2. Where-ObjectPowerShell 的万能过滤器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-Object6.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-ObjectPowerShell 的万能过滤器Where-Object是 PowerShell 中最常用的过滤命令之一。它的作用很简单让每一个管道对象都经过一段判断逻辑条件为 True 就保留条件为 False 就丢弃。最典型的写法如下Get-Service|Where-Object{$_.Status-eqRunning}这条命令的意思是获取所有服务 ↓ 逐个检查服务对象 ↓ 如果当前服务的 Status 等于 Running ↓ 保留这个服务对象2.1 标准语法推荐优先掌握我更推荐初学者优先记住完整标准写法命令|Where-Object{条件表达式}例如Get-Service|Where-Object{$_.Status-eqRunning}这里有两个关键点部分含义$_当前正在处理的管道对象{ }过滤脚本块返回$true或$false标准语法虽然比简写长一点但可读性最好也最适合写进脚本、笔记和企业内部 SOP。2.2$_表示当前对象例如Get-Service|Where-Object{$_.Status-eqRunning}在这条命令中$_每次代表一个服务对象。可以理解成第 1 次$_ 第一个服务 第 2 次$_ 第二个服务 第 3 次$_ 第三个服务 ……每个对象都会执行一次{ $_.Status -eq Running }。如果结果为$true这个对象会继续留在管道中。如果结果为$false这个对象就会被过滤掉。2.3 Where-Object 的工作原理上图很好地解释了 Where-Object 的处理过程管道输入多个对象Where-Object 逐个检查对象脚本块返回 True / FalseTrue 的对象保留False 的对象丢弃。Where-Object 不是一次性判断全部对象而是逐个对象执行过滤条件。3. Where-Object 的标准写法、简写与多条件过滤3.1 标准写法推荐写法Get-Service|Where-Object{$_.Status-eqRunning}这类写法适合单条件过滤多条件过滤脚本中长期使用后续扩展逻辑给同事交接命令。3.2 v3 简写写法PowerShell v3 之后支持简写Get-Service|Where Status-eqRunning这条命令和下面写法类似Get-Service|Where-Object{$_.Status-eqRunning}简写适合临时命令行输入但我不建议在复杂脚本中大量使用。原因是多条件时可读性下降不利于初学者理解$_复杂表达式容易写乱不适合写成培训文档或 SOP。简写可以会但标准写法必须熟。3.3 多条件过滤示例例如筛选正在运行且启动类型为手动的服务。Get-Service|Where-Object{$_.Status-eqRunning-and$_.StartType-eqManual}这里使用了-and表示两个条件都必须成立。也可以写成更清晰的多行版本Get-Service|Where-Object{($_.Status-eqRunning)-and($_.StartType-eqManual)}当条件变复杂时建议使用括号增强可读性。以后回头排查脚本时会非常省时间。3.4 典型布尔逻辑示例筛选名称为conhost或svchost并且仍在响应的进程Get-Process|Where-Object{$_.Name-in(conhost,svchost)-and$_.Responding}这里的逻辑是名称在conhost、svchost之中同时进程处于响应状态。-in很适合判断“某个值是否在一个集合里”。4. PSICLM迭代命令行模型把复杂需求拆成 5 步很多人写 PowerShell 命令时最大的问题不是不会某个命令而是喜欢一次性写完终极命令。结果就是一写就错错了不知道是哪一段错输出不符合预期只能靠猜改命令。更稳的方法是使用PSICLMPowerShell Iterative Command-Line Model迭代命令行模型。它的核心思想是不要一次写完复杂命令而是先跑通最小子问题再逐步叠加。4.1 示例需求需求统计除 PowerShell 进程外虚拟内存 VM 占用最高的 10 个进程的 VM 总和。如果直接写最终命令很容易出错。更推荐拆成 5 步。4.2 第一步先获取进程Get-Process先确认你拿到的是进程对象。可以进一步查看属性Get-Process|Get-Member4.3 第二步排除 PowerShell 本体Get-Process|Where-Object{$_.Name-notlikepowershell*}这里先过滤掉 PowerShell 相关进程避免统计时把当前操作环境也算进去。4.4 第三步按 VM 降序排序Get-Process|Where-Object{$_.Name-notlikepowershell*}|Sort-ObjectVM-DescendingSort-Object VM -Descending表示按 VM 从高到低排序。4.5 第四步只取前 10 个Get-Process|Where-Object{$_.Name-notlikepowershell*}|Sort-ObjectVM-Descending|Select-Object-First 10这一步可以先看 Top 10 是否符合预期。4.6 第五步统计 VM 总和Get-Process|Where-Object{$_.Name-notlikepowershell*}|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-eqRunning}这里$_表示当前正在检查的服务对象。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-eqRunning}这里有两个$_但它们不是同一个含义。第一个$_Where-Object{$_-notlike*dc}表示Get-Content .\names.txt读出来的每一行字符串也就是计算机名。第二个$_Where-Object{$_.Status-eqRunning}表示Get-Service返回的服务对象。5.5 一张表看懂$_作用域位置$_代表什么Get-Content …Where-Object { $_ }Get-ServiceWhere-Object { $_ }Get-ProcessForEach-Object { $_ }Select-Object {nX;e{$_.Name}}当前输入对象普通命令行直接写$_通常无意义或报错判断$_含义的关键不是看它长什么样而是看它前面的管道输入对象是什么。6. 远程与性能意识把过滤推到数据源上一篇讲过“左过滤”这一篇仍然要强调Where-Object 很强但它不一定应该成为第一选择。6.1 优先级-Filter Where-Object推荐顺序是能用原生命令参数过滤 ↓ 就不要先全量取回对象 ↓ 不能参数过滤时 ↓ 再使用 Where-Object例如 AD 查询Get-ADComputer-FilterName -like DC*优于Get-ADComputer-Filter*|Where-Object{$_.Name-likeDC*}原因很简单前者在 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-likeDC*}推荐Get-ADComputer-FilterName -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-eqRunning}错误$ServiceName$_.Name如果外面没有管道脚本块$_就没有明确的当前对象来源。7.4 坑位四括号子管道作用域没分清例如Get-Service-ComputerName(Get-Content.\names.txt|Where-Object{$_-notlike*dc})|Where-Object{$_.Status-eqRunning}两个$_的含义不同括号内部的$_是字符串括号外部的$_是服务对象。遇到多层管道时一定要先问当前$_到底是哪一种对象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,FullName8.4 只列出“安全更新”的补丁Get-HotFix-DescriptionSecurity Update这里不需要Where-Object因为Get-HotFix已经提供了-Description参数。这就是“能参数过滤就不要 Where”的典型例子。8.5 查找 Conhost 或 Svchost 且运行中的进程方式一先用名称过滤再判断响应状态Get-Process-Name conhost,svchost|Where-Object{$_.Responding}方式二完全使用 Where-ObjectGet-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-Member9.2 一张流程图判断该怎么过滤有没有需要不需要需要筛选对象Cmdlet 是否有过滤参数优先使用过滤参数使用 Where-Object是否还需要复杂条件继续接 Where-Object进入 Select / Sort / Export9.3 推荐命令结构数据源命令|Where-Object{条件}|Select-Object需要的属性|Sort-Object排序属性|Export-Csv输出文件实际示例Get-Service|Where-Object{$_.Status-eqRunning}|Select-ObjectName,DisplayName,Status|Sort-ObjectName|Export-Csv.\RunningServices.csv-NoTypeInformation-Encoding UTF810. 我的理解Where-Object 是过滤器不是万能第一步学完这一章后我对 Where-Object 的理解是Where-Object 很强但它应该是“必要时使用”而不是“默认第一选择”。在日常 Windows 运维中我们经常会写类似命令Get-Service|Where-Object{$_.Status-eqRunning}这没有问题因为Get-Service没有直接按Status过滤的参数。但如果命令本身已经支持过滤例如Get-Process-Name notepadGet-Service-Names*Get-HotFix-DescriptionSecurity UpdateGet-ADComputer-FilterName -like DC*那就应该优先使用这些原生过滤能力。PowerShell 写得好不好不只看命令能不能跑还要看它是否少取无关数据、是否容易维护、是否方便排错。对企业桌面运维来说这个思路尤其重要。比如查询远程服务批量检查补丁筛选域内计算机扫描大目录文件汇总日志或故障对象。这些场景一旦数据量变大过滤位置就会直接影响速度和稳定性。真正成熟的 PowerShell 使用习惯是先让数据源少吐数据再让管道精细处理数据。11. 总结过滤越靠左命令越稳这篇文章围绕 PowerShell 第 11 章“过滤和比较下”重点整理了以下内容Where-Object 是 PowerShell 的万能过滤器。标准语法Where-Object { $_.属性 -运算符 值 }最值得掌握。$_表示当前管道对象但只在支持脚本块的上下文中有效。v3 简写可以了解但复杂条件建议使用标准写法。复杂命令不要一次写完应使用 PSICLM 迭代命令行模型逐步构建。括号子管道里的$_和外层$_不是同一个作用域。远程和大数据量场景下要尽量把过滤推到数据源。不要混淆屏幕列头和真实属性名真实属性以Get-Member为准。能用命令参数过滤就不要先全量取回再 Where-Object。过滤越靠左传输越少计算越轻命令越稳。Where-Object 不是错错的是在可以左过滤的场景里把所有对象先拉回来再过滤。推荐做法是先参数过滤再 Where-Object最后 Select、Sort、Export。这套思维掌握后后续学习批量处理、远程管理、日志分析和自动化巡检都会更顺。最后用一句话总结PowerShell 过滤不是只会 Where-Object而是知道什么时候不用 Where-Object。参考资料PowerShell 官方帮助系统Get-Help Where-ObjectGet-Help about_Comparison_OperatorsGet-Help about_Logical_OperatorsGet-Help Get-ServiceGet-Help Get-ProcessGet-Help Get-ChildItemGet-Help Measure-ObjectGet-Help Sort-ObjectGet-Help Select-Object 返回顶部点击回到顶部
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2574333.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!