跳到主要内容

管道与对象

管道是 PowerShell 最核心的特性之一。与传统 shell 传递文本不同,PowerShell 管道传递的是 .NET 对象,这使得数据处理更加灵活和强大。

理解对象管道

对象 vs 文本

在传统 shell(如 bash 或 cmd)中,命令输出是文本,需要解析文本才能提取信息:

ps aux | grep chrome | awk '{print $2}'

PowerShell 传递的是对象,可以直接访问属性和方法:

Get-Process chrome | Select-Object Id

查看对象类型和成员

使用 Get-Member 查看对象的类型和可用成员:

Get-Process | Get-Member

输出示例:

   TypeName: System.Diagnostics.Process

Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
...

查看特定成员:

Get-Process | Get-Member -MemberType Property
Get-Process | Get-Member -MemberType Method

管道操作符

基本管道

使用 | 将一个命令的输出传递给另一个命令:

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

链式管道

多个命令可以串联:

Get-Process |
Where-Object { $_.CPU -gt 100 } |
Sort-Object CPU -Descending |
Select-Object -First 5

筛选对象

Where-Object

Where-Object 根据条件过滤对象:

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

简化语法(PowerShell 3.0+):

Get-Service | Where-Object Status -eq "Running"

使用多个条件:

Get-Process | Where-Object { $_.CPU -gt 100 -and $_.WorkingSet -gt 100MB }

使用 -or 逻辑:

Get-Service | Where-Object { $_.Status -eq "Running" -or $_.Status -eq "Stopped" }

Select-Object

Select-Object 选择对象的特定属性:

Get-Process | Select-Object Name, Id, CPU

选择前 N 个对象:

Get-Process | Select-Object -First 5
Get-Process | Select-Object -Last 5

跳过对象:

Get-Process | Select-Object -Skip 5
Get-Process | Select-Object -Skip 5 -First 5

选择唯一值:

Get-Process | Select-Object Name -Unique

创建计算属性:

Get-Process | Select-Object Name, 
@{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSet / 1MB, 2)}}

Select-String

在文本中搜索模式:

Get-Content "C:\Logs\app.log" | Select-String "Error"

使用正则表达式:

Get-Content "C:\Logs\app.log" | Select-String "\d{4}-\d{2}-\d{2}"

搜索文件内容:

Select-String -Path "C:\Logs\*.log" -Pattern "Exception" -Context 2,2

排序对象

Sort-Object

按属性排序:

Get-Process | Sort-Object CPU
Get-Process | Sort-Object CPU -Descending

按多个属性排序:

Get-Process | Sort-Object CPU -Descending, Name

使用计算属性排序:

Get-ChildItem | Sort-Object { $_.Length } -Descending

分组对象

Group-Object

按属性分组:

Get-Service | Group-Object Status

输出示例:

Count Name                      Group
----- ---- -----
87 Running {AdobeARMservice, Appinfo, AudioSrv...}
12 Stopped {AJRouter, ALG, AppMgmt...}

按计算属性分组:

Get-ChildItem | Group-Object Extension

使用 -NoElement 省略组成员:

Get-Service | Group-Object Status -NoElement

统计对象

Measure-Object

计算统计值:

Get-Process | Measure-Object WorkingSet -Sum -Average -Maximum -Minimum

统计行数:

Get-Content "file.txt" | Measure-Object -Line

统计字符数:

"Hello World" | Measure-Object -Character -Word

比较对象

Compare-Object

比较两个对象集合:

$set1 = 1, 2, 3, 4, 5
$set2 = 3, 4, 5, 6, 7

Compare-Object $set1 $set2

输出:

InputObject SideIndicator
----------- -------------
6 =>
7 =>
1 <=
2 <=
  • <= 表示只在第一个集合中存在
  • => 表示只在第二个集合中存在

比较文件内容:

Compare-Object (Get-Content "file1.txt") (Get-Content "file2.txt")

比较对象属性:

Compare-Object $list1 $list2 -Property Name, Id

格式化输出

Format-Table

表格格式输出:

Get-Process | Format-Table Name, Id, CPU -AutoSize

自动换行:

Get-Process | Format-Table Name, Id, CPU -Wrap

Format-List

列表格式输出:

Get-Process chrome | Format-List *

指定属性:

Get-Process | Format-List Name, Id, CPU, WorkingSet

Format-Wide

宽格式输出,每行显示多个对象:

Get-Service | Format-Wide Name -Column 4

Format-Custom

自定义视图:

Get-Process | Format-Custom

导出数据

Export-Csv

导出为 CSV 文件:

Get-Process | Export-Csv -Path "processes.csv" -NoTypeInformation

追加到现有文件:

Get-Process | Export-Csv -Path "processes.csv" -Append

ConvertTo-Csv

转换为 CSV 字符串:

Get-Process | Select-Object Name, Id, CPU | ConvertTo-Csv

Export-Clixml

导出为 XML 格式,保留类型信息:

Get-Process | Export-Clixml -Path "processes.xml"

导入:

Import-Clixml -Path "processes.xml"

ConvertTo-Json

转换为 JSON 格式:

Get-Process chrome | Select-Object Name, Id, CPU | ConvertTo-Json

指定深度:

$object | ConvertTo-Json -Depth 5

ConvertTo-Html

转换为 HTML 格式:

Get-Process | ConvertTo-Html -Property Name, Id, CPU |
Out-File "processes.html"

添加标题和 CSS:

Get-Process |
ConvertTo-Html -Title "进程列表" -CssUri "style.css" |
Out-File "processes.html"

Tee-Object

同时输出到文件和管道:

Get-Process | Tee-Object -FilePath "processes.txt" | Select-Object -First 5

输出到变量:

Get-Process | Tee-Object -Variable processes | Select-Object -First 5
$processes | Measure-Object

管道实战示例

分析日志文件

Get-Content "C:\Logs\app.log" |
Where-Object { $_ -match "ERROR" } |
ForEach-Object {
if ($_ -match "(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ERROR (.+)") {
[PSCustomObject]@{
Timestamp = $matches[1]
Message = $matches[2]
}
}
} |
Group-Object { $_.Timestamp.Split(' ')[0] } |
Sort-Object Count -Descending |
Select-Object Name, Count |
Format-Table -AutoSize

查找大文件

Get-ChildItem -Path "C:\" -Recurse -ErrorAction SilentlyContinue |
Where-Object { -not $_.PSIsContainer -and $_.Length -gt 100MB } |
Select-Object FullName,
@{Name="Size(MB)";Expression={[math]::Round($_.Length/1MB, 2)}},
LastWriteTime |
Sort-Object "Size(MB)" -Descending |
Format-Table -AutoSize

服务状态报告

Get-Service |
Group-Object Status |
Select-Object Name, Count |
Format-Table -AutoSize

Get-Service |
Where-Object { $_.Status -eq "Stopped" -and $_.StartType -eq "Automatic" } |
Select-Object Name, DisplayName, Status |
Format-Table -AutoSize

进程资源分析

Get-Process |
Where-Object { $_.WorkingSet -gt 100MB } |
Select-Object Name,
@{Name="CPU(s)";Expression={[math]::Round($_.CPU, 2)}},
@{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSet/1MB, 2)}},
@{Name="Handles";Expression={$_.HandleCount}} |
Sort-Object "Memory(MB)" -Descending |
Format-Table -AutoSize

系统信息收集

$systemInfo = [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
OS = (Get-CimInstance Win32_OperatingSystem).Caption
CPU = (Get-CimInstance Win32_Processor).Name
TotalMemory = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory/1GB, 2)
FreeMemory = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory/1MB, 2)
DiskSpace = Get-Volume -DriveLetter C | Select-Object -ExpandProperty SizeRemaining
}

$systemInfo | Format-List

下一步

掌握了管道与对象后,接下来学习 常用 Cmdlet,了解日常管理中最常用的命令。