ForEach-Object 是什么
ForEach-Object 对管道里的每个对象执行一次操作,是「拿到一批对象后逐个动手」的通用工具。它既能做纯计算,也能产生副作用,比如调用方法、启动服务、写文件、调用外部程序。脚本块里用 $_ 指代当前对象,也可以用 -Begin、-Process、-End 三个块分别做初始化、逐项处理与收尾。PowerShell 7 起还支持并发参数,让互不依赖的逐项任务同时跑,这在批量巡检大量主机时能显著缩短耗时。
基本信息
| 适用平台 | Windows PowerShell 5.1 与 PowerShell 7 及以上(并发参数仅 7 及以上) |
|---|---|
| 语法 | ForEach-Object { 处理逻辑 } 或 ForEach-Object -Begin {} -Process {} -End {} |
| 别名 | 百分号(交互时常用,脚本里建议写全名) |
| 并发参数 | -Parallel 并行执行、-ThrottleLimit 控制并发数量(PowerShell 7 及以上) |
| 当前对象 | 脚本块里用 $_,也可以显式声明参数名接收当前对象 |
| 与语句的区别 | ForEach-Object 走管道流式处理,foreach 语句会先取完整集合再循环 |
典型使用场景
- 批量重启或停止服务:先筛选出目标再从管道逐项执行
- 批量落盘:为每条记录生成单独的文件或追加写入日志
- 批量调用外部程序:对每个目标主机执行一次探测命令
- 逐项计算:把对象的某个属性做换算或拼接成新字符串
- 带初始化的处理:用开始块建立计数器或连接,结束时统一收尾
- 并发执行:对互不依赖的主机列表并行做巡检
常用示例
常用示例
# 逐项取下运行中服务的名称
Get-Service | Where-Object Status -eq Stopped | ForEach-Object { $_.Name }
# 逐项计算:把字节数换算成 KB
Get-ChildItem *.log | ForEach-Object { $_.Length / 1KB }
# 带初始化与收尾:统计处理条数
$count = 0
Get-ChildItem C:\Logs -File | ForEach-Object -Begin { $count = 0 } -Process { $count++ } -End { "共处理 $count 个文件" }
# 批量重启:先筛选,再逐项执行
Get-Service -Name Spooler, W32Time | ForEach-Object { Restart-Service $_.Name }
# 并发处理多个主机(PowerShell 7 及以上)
1..4 | ForEach-Object -Parallel { "主机 $_" } -ThrottleLimit 2参数与用法对照
| 用法 | 作用 | 注意点 |
|---|---|---|
| -Process 块 | 对每个对象执行处理逻辑 | 默认块,省略时整段脚本块即处理逻辑 |
| -Begin 块 | 处理开始前执行一次 | 适合初始化累加器或连接 |
| -End 块 | 处理结束后执行一次 | 适合输出汇总结果 |
| -Parallel | 并行处理管道对象(版本要求较高) | 脚本块内变量需用 using 前缀传入 |
| -ThrottleLimit | 限制并发数量 | 并发过高会压垮目标主机与网络 |
| -InputObject | 直接传入集合而非走管道 | 会作为单个对象处理,行为与管道不同 |
与 foreach 语句的差异
| 对比项 | ForEach-Object | foreach 语句 |
|---|---|---|
| 数据来源 | 管道逐个流入 | 先取出完整集合 |
| 内存占用 | 流式处理,占用小 | 集合全量在内存中 |
| 能否提前退出 | 可在脚本块内使用返回或中断控制 | 支持 break 与 continue |
| 适用位置 | 管道中任意位置 | 脚本语句块中 |
只做纯取值与换算时,优先用 Select-Object,它不需要为每条记录执行完整脚本块,速度更快;需要副作用时才交给 ForEach-Object。
并发参数只适合互不依赖的任务。若脚本块内要修改共享变量或写同一个文件,并发会带来竞争,应改用串行处理或在每个分支里独立写目标。
脚本块里也能直接调用对象的方法,例如对每个服务对象调用停止方法。方法与属性不同,必须带上括号;如果只是想取值,用属性即可,不必包一层循环。