PowerShell 进阶
本篇在基础篇之上,讲解模块、对象、错误处理、脚本编写、数据格式与自动化。 建议先掌握变量、管道、流程控制和函数。
1. 模块(Module)
模块是打包好的命令集合,用于扩展 PowerShell 功能。
Get-Module # 查看当前会话已加载的模块
Get-Module -ListAvailable # 查看系统已安装的模块
Import-Module Pester # 导入模块
从 PowerShell Gallery(在线仓库)安装第三方模块:
Find-Module -Name PSReadLine # 搜索模块
Install-Module -Name Pester -Scope CurrentUser # 安装
Update-Module -Name Pester # 更新
首次安装可能提示需要
NuGet提供程序或信任仓库,输入Y确认即可。
2. 对象与成员
PowerShell 中命令返回的是对象,不只是文本。用 Get-Member 查看对象有哪些属性和方法。
Get-Process | Get-Member # 查看进程对象的成员
Get-Date | Get-Member -MemberType Method # 只看方法
访问属性与方法:
$p = Get-Process -Name explorer
$p.Name # 属性
$p.CPU # 属性
$p.Kill() # 方法(结束进程)
2.1 自定义对象
$obj = [PSCustomObject]@{
Name = "张三"
Age = 18
}
$obj.Name # 张三
2.2 计算属性
Select-Object 可以基于现有属性计算出新属性:
Get-Process |
Select-Object Name,
@{Name = "内存MB"; Expression = { [math]::Round($_.WorkingSet / 1MB, 2) }} |
Sort-Object 内存MB -Descending |
Select-Object -First 5
3. 错误处理
3.1 try / catch / finally
try {
$content = Get-Content -Path "不存在的文件.txt" -ErrorAction Stop
}
catch {
Write-Output "出错了:$($_.Exception.Message)"
}
finally {
Write-Output "无论如何都会执行"
}
要让
Get-Content等命令触发catch,需加-ErrorAction Stop,否则非终止性错误不会进入 catch。
3.2 错误处理偏好
$ErrorActionPreference = "Stop" # 全局:所有错误都当作终止性错误
$ErrorActionPreference = "Continue" # 默认:继续执行
Get-ChildItem -ErrorAction SilentlyContinue # 忽略错误,静默继续
3.3 错误信息对象
try {
1 / 0
}
catch {
$_.Exception.Message # 错误消息
$_.ScriptStackTrace # 调用栈
$_.InvocationInfo.Line # 出错的那行
}
4. 编写与运行脚本
4.1 脚本文件
把命令保存为 .ps1 文件即可成为脚本:
# hello.ps1
param(
[string]$Name = "世界"
)
Write-Output "你好,$Name"
运行:
.\hello.ps1 # 当前位置运行
.\hello.ps1 -Name "张三"
powershell -ExecutionPolicy Bypass -File .\hello.ps1 # 绕过执行策略
4.2 参数进阶
param(
[Parameter(Mandatory = $true)] # 必填
[string]$Path,
[ValidateSet("Dev", "Prod")] # 限定取值
[string]$Env = "Dev",
[switch]$Verbose # 开关参数(不带值)
)
if ($Verbose) { Write-Output "详细模式" }
调用:
.\deploy.ps1 -Path "C:\app" -Env Prod -Verbose
4.3 支持管道的函数
使用 begin / process / end 三个块处理管道输入:
function Get-Even {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
[int]$Number
)
begin { Write-Output "开始处理" }
process { if ($Number % 2 -eq 0) { Write-Output $Number } }
end { Write-Output "处理结束" }
}
1..10 | Get-Even
5. 文本与正则
$text = "订单号:A12345,金额:99.5 元"
# 提取数字
$text -match "\d+" # True
$Matches[0] # 第一个匹配
# 提取所有匹配
[regex]::Matches($text, "\d+") | ForEach-Object { $_.Value }
# 替换
$text -replace "金额:\d+(\.\d+)?", "金额:***"
# 拆分
"a,b,c" -split ","
-replace、-match默认使用正则表达式;-like使用通配符。
6. 数据格式:CSV 与 JSON
6.1 CSV
# 读取 CSV(自动转为对象)
$rows = Import-Csv -Path "users.csv"
$rows | Where-Object { $_.Age -gt 18 }
# 导出 CSV
$data | Export-Csv -Path "out.csv" -NoTypeInformation -Encoding UTF8
6.2 JSON
# 字符串 → 对象
$json = '{"name":"张三","age":18}'
$obj = $json | ConvertFrom-Json
$obj.name # 张三
# 对象 → JSON
$obj | ConvertTo-Json -Depth 5
# 读写文件
Get-Content "config.json" -Raw | ConvertFrom-Json
$obj | ConvertTo-Json | Set-Content "config.json" -Encoding UTF8
6.3 其他格式
Get-Process | Export-Clixml out.xml # XML 序列化
Import-Clixml out.xml # 反序列化
7. 文件与目录进阶
# 递归查找并删除 30 天前的日志
Get-ChildItem -Path ".\logs" -Filter "*.log" -Recurse |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Remove-Item -Force
# 批量重命名
Get-ChildItem -Filter "*.txt" | Rename-Item -NewName { $_.Name -replace " ", "_" }
# 计算目录总大小
(Get-ChildItem -Recurse -File | Measure-Object Length -Sum).Sum / 1MB
# 查找大文件
Get-ChildItem -Recurse -File | Sort-Object Length -Descending | Select-Object -First 10
8. 远程与自动化
8.1 远程执行(WinRM)
# 在远程主机执行命令
Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Process }
# 建立交互式会话
Enter-PSSession -ComputerName Server01
Exit-PSSession
需目标主机启用 WinRM(
Enable-PSRemoting -Force)并具备凭据。
8.2 后台任务与作业
$job = Start-Job -ScriptBlock { Start-Sleep 5; "完成" }
Get-Job
Receive-Job -Id $job.Id -Wait
Remove-Job -Id $job.Id
8.3 计划任务
$action = New-ScheduledTaskAction -Execute "pwsh" -Argument "-File C:\scripts\backup.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At 3am
Register-ScheduledTask -TaskName "每日备份" -Action $action -Trigger $trigger
9. 性能与最佳实践
- 优先使用管道与内置命令,避免手写循环(性能更好)。
- 筛选尽量前置:
Get-ChildItem -Filter比| Where-Object快。 - 大量输出时避免字符串拼接,改用数组或
[System.Text.StringBuilder]。 - 脚本开头写
[CmdletBinding()],获得-Verbose、-Debug等通用参数。 - 使用
#Requires -Version 7声明脚本所需的最低版本。 - 变量命名用有意义的名字,函数用「动词-名词」并确保动词在
Get-Verb列表中。
#Requires -Version 7.0
[CmdletBinding()]
param(
[string]$Path = "."
)
10. 实用片段合集
测速 / 计时
Measure-Command { 1..100000 | ForEach-Object { $_ * 2 } }
生成随机密码
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 16 | ForEach-Object { [char]$_ })
查看端口占用
Get-NetTCPConnection -LocalPort 8080 | Select-Object LocalAddress, State, OwningProcess
递归列出目录树
Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer } | Select-Object FullName
发送 HTTP 请求
$resp = Invoke-RestMethod -Uri "https://api.github.com/repos/PowerShell/PowerShell"
$resp.stargazers_count
11. 学习资源
- 官方文档:learn.microsoft.com/powershell
- PowerShell Gallery(模块仓库):powershellgallery.com
- 源码仓库:github.com/PowerShell/PowerShell
- 秘籍与示例:PowerShell-Docs
结合基础篇反复练习,多写小脚本解决日常重复工作,是掌握 PowerShell 最快的路径。