powershell中用@()包裹管道可强制将输出转为数组,确保支持.count、索引访问等集合操作;不加则单对象时非数组、零输出时为$null,易引发错误。
powershell 中的管道默认是流式处理对象,每个命令输出的对象会逐个传递给下一个命令,而不是自动聚合成一个集合。但有时你需要把整个管道结果“收拢”成一个数组或列表(比如后续要计数、索引访问、重复使用),这时就需要显式合并。
直接用数组构造符 @() 包裹管道
这是最常用、最可靠的方式:
$allItems = @(Get-ChildItem C:\Temp\*.log | Where-Object Length -gt 1024 | Sort-Object LastWriteTime)
@() 强制将管道输出封装为数组(即使只有一项或零项),确保 $allItems 是 System.Object[] 类型,支持 .Count、[0] 索引、ForEach-Object 等集合操作。
- 如果不加
@(),单个对象时$allItems就是那个对象本身(不是数组),调用.Count会返回1(隐式行为),但[0]会报错; - 零输出时,
@()得到空数组@(),.Count为0;不加则得到$null,.Count是$null。
用逗号运算符 , 显式构造数组(适合少量已知对象)
$collection = (Get-Process notepad), (Get-Service spooler) # 注意:这里不是管道,而是两个独立命令,用逗号连接 → 得到含两个对象的数组
这种方式不适用于动态管道流,仅适合拼接几个明确结果。
用 @(...) + ForEach-Object 处理中间聚合逻辑
如果需要在合并前对每个对象做转换,再统一收集:
$namesAndSizes = @(
Get-ChildItem *.txt |
ForEach-Object { [PSCustomObject]@{ Name = $_.Name; Size = $_.Length } }
)
ForEach-Object 在管道中逐个生成新对象,外层 @() 把它们全部收进数组。
不推荐:依赖 + 运算符累加(性能差、语义不清)
$result = @()
Get-ChildItem *.log | ForEach-Object { $result += $_ } # ❌ 避免
+= 对数组是复制重建,大数据量时非常慢;且易引发作用域问题(尤其在函数内)。
用 @() 包裹管道是最简洁、高效、符合 PowerShell 惯用法的做法。











