什么是
本文提供了 PowerShell 脚本的全面最佳实践指南,重点介绍代码结构、输出格式、错误处理、性能优化及安全措施。
为什么
遵循 PowerShell 脚本的最佳实践可以确保脚本具备良好的可读性、可维护性、安全性和高效性。它有助于减少技术债务,提升团队协作效率,并降低生产环境中的风险。
如何实施
工具与控制器设计
判断你在编写“工具”还是“控制器”
- 工具:可复用的函数或模块。
- 控制器:用于自动化特定任务,非复用型脚本。
使代码模块化
- 利用函数和脚本模块提升复用性。
使用标准命名规范
- 遵循 动词-名词 格式,使用 PowerShell 官方动词(
Get-Verb
)。
参数命名标准化
- 使用如
$ComputerName
这样的通用名称,避免自定义前缀。
工具应输出原始数据
- 保持数据的灵活性,避免过度处理。
控制器应输出格式化数据
- 提供用户友好的报告格式。
示例
function Get-DiskInfo {
param ([string]$ComputerName)
Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName
}
避免重复造轮子
优先使用内置 cmdlet,如 Test-Connection
,而非自定义功能。
# 推荐
Test-Connection $ComputerName -Quiet
编写参数块
始终编写帮助文档
使用注释形式的 .SYNOPSIS
、.DESCRIPTION
和至少一个 .EXAMPLE
。
function Test-Help {
<#
.SYNOPSIS
展示正确的帮助文档格式。
.EXAMPLE
Test-Help -MandatoryParameter "示例"
使用必需参数运行 Test-Help 函数。
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[Alias("MP")]
[String]$MandatoryParameter
)
}
使用 [CmdletBinding()]
启用如 -Verbose
、-Debug
、-ErrorAction
等通用参数。
支持 -WhatIf 和 -Confirm
涉及状态变更的命令应使用 SupportsShouldProcess
。
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")]
param ([switch]$Force)
强类型参数
明确指定参数类型,提升代码的可靠性与可读性。
param (
[string]$Name,
[int]$Count
)
正确使用 [switch]
- 默认值为
$false
。 - 仅作为布尔值处理,避免三态逻辑。
输出格式化
除非必要,避免使用 Write-Host
根据场景选择 Write-Verbose
、Write-Debug
或 Write-Output
。
使用 Write-Progress 显示进度
Write-Progress -Activity "处理中" -Status "完成50%" -PercentComplete 50
为自定义对象使用格式文件
通过 .format.ps1xml
文件定义格式,而非内联格式化。
每次仅输出一种对象类型
使用 [OutputType()]
,避免类型混合。
错误处理最佳实践
cmdlet 中使用 -ErrorAction Stop
确保通过 try-catch
捕获错误。
try {
Get-Item "C:\无效路径" -ErrorAction Stop
} catch {
Write-Warning "未找到指定项。"
}
对非 cmdlet 操作使用 $ErrorActionPreference
在风险操作前临时设置为 'Stop'
。
避免使用标志位和 $? 判断错误
优先使用结构化的 try-catch
处理机制。
在 catch 中立即复制 $Error[0] 或 $_
catch {
$errorDetails = $_
Write-Error "发生错误: $($errorDetails.Exception.Message)"
}
性能优化
PERF-01 需要时再衡量性能
利用 Measure-Command
评估不同方案。
Measure-Command {
foreach ($item in $data) { Process-Item $item }
}
PERF-02 平衡性能与可读性
- 小型数据集优先考虑可读性。
- 大型数据集时采用流处理或 .NET 技术。
可读性优先:
$content = Get-Content -Path file.txt
foreach ($line in $content) {
Do-Something -Input $line
}
性能优化:
Get-Content -Path file.txt | ForEach-Object {
Do-Something -Input $_
}
使用 .NET 提升性能:
$sr = New-Object System.IO.StreamReader "file.txt"
while ($sr.Peek() -ge 0) {
$line = $sr.ReadLine()
Do-Something -Input $line
}
PERF-03 优先使用语言特性
- 语言结构(如
foreach
)> .NET 方法 > 脚本 > cmdlet/管道。 - 避免过早优化,务必测量后再优化。
安全性最佳实践
始终使用 PSCredential 管理凭据
避免明文密码,使用 [Credential()]
参数。
param (
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential
)
调用 API 时:
$Insecure.SetPassword($Credential.GetNetworkCredential().Password)
使用 SecureString 处理敏感数据
$Secure = Read-Host -Prompt "请输入敏感数据" -AsSecureString
安全转换为明文:
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secure)
$PlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
安全保存凭据
Get-Credential | Export-CliXml -Path C:\secure\cred.xml
$Credential = Import-CliXml -Path C:\secure\cred.xml
保存加密字符串
ConvertFrom-SecureString -SecureString $Secure | Out-File -Path "${Env:AppData}\secure.bin"
$Secure = Get-Content -Path "${Env:AppData}\secure.bin" | ConvertTo-SecureString
结论
通过遵循以上 PowerShell 最佳实践,您可以编写出稳健、高效且安全的脚本,适用于各种自动化场景。始终在可读性、性能与安全性之间寻求最佳平衡,打造高质量的解决方案。