一、变量使用不当引发的"血案"

新手最容易犯的错误就是变量使用不规范。比如下面这个典型例子:

# 错误示例:未声明变量直接使用
$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) {
    # 有效邮箱
}

七、最佳实践总结

  1. 始终使用-WhatIf参数测试破坏性命令
  2. 为重要函数编写帮助注释
  3. 使用PSScriptAnalyzer进行静态检查
  4. 考虑使用类替代传统函数(PowerShell 5.0+)
  5. 日志记录要详细但不过度

示例类定义:

class SystemMonitor {
    [string]$ComputerName
    
    SystemMonitor([string]$name) {
        $this.ComputerName = $name
    }
    
    [void] CheckStatus() {
        # 监控逻辑
    }
}

$monitor = [SystemMonitor]::new("SERVER01")
$monitor.CheckStatus()

记住,好的PowerShell脚本应该像讲故事一样清晰,每个函数都是一个段落,每行代码都是一个句子。保持简洁但不简单,强大但不复杂,这才是脚本之道的精髓。