一、变量使用不当引发的"血案"
新手最容易犯的错误就是变量使用不规范。比如下面这个典型例子:
# 错误示例:未声明变量直接使用
$user = "admin"
Write-Host "当前用户是:" + $User # 注意大小写不一致
这里的问题在于PowerShell是大小写不敏感的,但$user和$User实际上是同一个变量。更规范的写法应该是:
# 正确示例:统一变量命名风格
[string]$userName = "admin" # 显式声明类型
Write-Host "当前用户是:$userName" # 使用字符串插值
变量作用域也是个坑。看这个函数示例:
function Test-Scope {
$private:count = 0 # 函数私有变量
$script:total = 100 # 脚本级变量
$global:max = 1000 # 全局变量
# 访问不同作用域变量
Write-Host "私有变量:$count"
}
二、管道操作中的性能陷阱
管道是PowerShell的亮点,但滥用会导致性能问题:
# 低效写法:多次管道操作
Get-Process | Where-Object { $_.CPU -gt 100 } |
Sort-Object -Property CPU -Descending |
Select-Object -First 10
# 高效写法:减少管道传递
Get-Process -ErrorAction SilentlyContinue |
Where-Object CPU -gt 100 -ErrorAction Stop |
Sort-Object CPU -Descending |
Select-Object -First 10
处理大文件时更要注意:
# 错误示例:一次性读取大文件
$content = Get-Content -Path "huge.log" # 内存爆炸!
# 正确做法:流式处理
Get-Content "huge.log" -ReadCount 1000 |
ForEach-Object {
# 分批处理逻辑
}
三、异常处理的艺术
很多脚本没有完善的错误处理:
# 危险写法:忽略所有错误
Remove-Item "*.tmp" -Force
# 安全写法:结构化异常处理
try {
Remove-Item "*.tmp" -Force -ErrorAction Stop
}
catch [System.IO.IOException] {
Write-Warning "文件被占用:$_"
}
catch {
Write-Error "未知错误:$_"
}
finally {
# 清理资源
}
对于需要重试的操作:
$retryCount = 3
$delay = 5
while ($retryCount -gt 0) {
try {
Invoke-RestMethod "https://api.example.com" -ErrorAction Stop
break
}
catch {
$retryCount--
if ($retryCount -eq 0) { throw }
Start-Sleep -Seconds $delay
}
}
四、模块化设计的智慧
避免写超长脚本,应该模块化:
# 模块文件:MyModule.psm1
function Get-SystemInfo {
param(
[Parameter(Mandatory)]
[string]$ComputerName
)
# 获取系统信息逻辑
}
function Set-SystemConfig {
# 配置系统参数
}
Export-ModuleMember -Function *-*
然后在主脚本中:
# 主脚本
Import-Module .\MyModule.psm1 -Force
Get-SystemInfo -ComputerName "SERVER01"
Set-SystemConfig -Param1 "Value"
五、远程管理的正确姿势
远程执行是常见需求,但要注意安全:
# 不安全示例:明文密码
$cred = New-Object pscredential("admin", (ConvertTo-SecureString "123456" -AsPlainText -Force))
# 安全做法:使用证书或CredSSP
$session = New-PSSession -ComputerName "server" -ConfigurationName "Microsoft.PowerShell32" -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
# 远程执行代码
}
批量管理多台服务器:
$servers = "web01","web02","db01"
$results = Invoke-Command -ComputerName $servers -ThrottleLimit 10 -ScriptBlock {
Get-Service | Where Status -eq "Running"
} -AsJob | Wait-Job | Receive-Job
六、高效字符串处理技巧
字符串拼接是个性能杀手:
# 低效写法:反复拼接
$output = ""
1..10000 | ForEach-Object {
$output += "Item $_`n" # 每次都会创建新字符串
}
# 高效写法:使用StringBuilder
$sb = [System.Text.StringBuilder]::new()
1..10000 | ForEach-Object {
[void]$sb.AppendLine("Item $_")
}
$output = $sb.ToString()
正则表达式优化:
# 预编译正则提升性能
[regex]$emailPattern = '^[^@]+@[^@]+\.[^@]+$'
if ("test@example.com" -match $emailPattern) {
# 有效邮箱
}
七、最佳实践总结
- 始终使用-WhatIf参数测试破坏性命令
- 为重要函数编写帮助注释
- 使用PSScriptAnalyzer进行静态检查
- 考虑使用类替代传统函数(PowerShell 5.0+)
- 日志记录要详细但不过度
示例类定义:
class SystemMonitor {
[string]$ComputerName
SystemMonitor([string]$name) {
$this.ComputerName = $name
}
[void] CheckStatus() {
# 监控逻辑
}
}
$monitor = [SystemMonitor]::new("SERVER01")
$monitor.CheckStatus()
记住,好的PowerShell脚本应该像讲故事一样清晰,每个函数都是一个段落,每行代码都是一个句子。保持简洁但不简单,强大但不复杂,这才是脚本之道的精髓。
评论