PowerShell 脚本编写

PowerShell 脚本编写全攻略(2025 版)

从“能跑”到“企业级可维护、可复用、可交付”的完整进化路线

1. 脚本基本结构(企业级必备模板)

#==========================================================================
# Script Name   : Backup-Database.ps1
# Description   : 每日自动备份指定数据库并清理旧备份
# Author        : 张三 (zhang.san@company.com)
# Created       : 2025-12-03
# Version       : 2.1.0
#==========================================================================

[CmdletBinding(
    SupportsShouldProcess = $true,
    ConfirmImpact = 'Medium'
)]
param (
    [Parameter(Mandatory=$true)]
    [string]$ServerInstance,

    [Parameter(Mandatory=$true)]
    [string[]]$DatabaseName,

    [string]$BackupPath = "\\nas\backup\db",

    [int]$RetentionDays = 30,

    [switch]$WhatIf
)

# 严格模式(推荐所有正式脚本第一行就打开)
Set-StrictMode -Version Latest

# 停止任何非终止错误(配合 try/catch 才能捕获)
$ErrorActionPreference = 'Stop'

# 记录开始时间(用于日志和耗时统计)
$ScriptStartTime = Get-Date
$LogTime = { (Get-Date).ToString('yyyy-MM-dd HH:mm:ss') }

Write-Verbose "$(&$LogTime) 脚本开始执行..."

2. 必须养成的 10 个黄金习惯

习惯正确写法错误写法
1. 总是加参数块param(…)直接在脚本里写 $args
2. 给参数加类型和验证[ValidateScript({Test-Path $_})][string]$Path裸 string
3. 使用 CmdletBinding[CmdletBinding(SupportsShouldProcess=$true)]没有
4. 使用 Write-Verbose 而不是 Write-HostWrite-Verbose “正在连接 $Server”Write-Host
5. 错误处理统一用 try/catchtry { … } catch { Write-Error $_ ; return }直接让错误打印
6. 所有函数都用高级函数写法function Backup-OneDB { [CmdletBinding()] param(…) … }function Backup-OneDB { … }
7. 路径全部用 Join-PathJoin-Path $BackupPath $FileName“$BackupPath\$FileName”
8. 脚本结束统一写总结Write-Host “耗时 $((Get-Date)-$ScriptStartTime)” -ForegroundColor Green直接结束
9. 脚本开头写帮助注释.SYNOPSIS / .EXAMPLE没有注释
10. 用 ShouldProcess 实现 -WhatIf/-Confirmif ($PSCmdlet.ShouldProcess($db, “备份数据库”)) { … }自己判断 $WhatIf

3. 企业级脚本必备功能模块(直接复制粘贴)

# 1. 日志函数(支持文件+控制台彩色)
function Write-Log {
    param(
        [Parameter(Mandatory)] [string]$Message,
        [ValidateSet('INFO','WARN','ERROR','DEBUG')] [string]$Level = 'INFO'
    )
    $color = switch($Level){
        'INFO'  {'White'}
        'WARN'  {'Yellow'}
        'ERROR' {'Red'}
        'DEBUG' {'Cyan'}
    }
    $logLine = "$(&$LogTime) [$Level] $Message"
    Write-Host $logLine -ForegroundColor $color
    $logLine | Out-File -FilePath "$PSScriptRoot\$(Split-Path $PSCommandPath -Leaf).log" -Append -Encoding UTF8
}

# 2. 统一的错误处理函数
function Handle-Error {
    param($ErrorRecord = $_)
    Write-Log "错误: $($ErrorRecord.Exception.Message)" 'ERROR'
    Write-Log "位置: $($ErrorRecord.InvocationInfo.ScriptLineNumber)" 'ERROR'
    exit 1
}

# 3. 主流程写在函数里(推荐)
function Main {
    try {
        foreach ($db in $DatabaseName) {
            if ($PSCmdlet.ShouldProcess($db, "备份数据库到 $BackupPath")) {
                Backup-OneDatabase -Server $ServerInstance -Database $db -Path $BackupPath
            }
        }
        Remove-OldBackups -Path $BackupPath -OlderThanDays $RetentionDays
    }
    catch { Handle-Error $_ }
}

# 4. 脚本最后统一调用
Main
Write-Log "脚本执行完成,耗时 $(((Get-Date) - $ScriptStartTime).ToString('hh\:mm\:ss'))" 'INFO'

4. 参数验证高级用法(让脚本“傻瓜式”)

param (
    [Parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName,

    [ValidateRange(1,65535)]
    [int]$Port = 1433,

    [ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
    [string]$IPAddress,

    [ValidateScript({ $_ -in (Get-ChildItem 'C:\Scripts\Configs\*.json').Name })]
    [string]$ConfigFile,

    [ValidateSet('Full','Differential','Log')]
    [string]$BackupType = 'Full'
)

5. 脚本签名(生产环境必须)

# 1. 获取企业代码签名证书(一次设置,永久有效)
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1

# 2. 对所有 .ps1 文件批量签名
Get-ChildItem *.ps1 -Recurse | Set-AuthenticodeSignature -Certificate $cert

# 3. 设置执行策略(推荐)
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine   # 允许运行本地签名脚本
Set-ExecutionPolicy AllSigned -Scope LocalMachine      # 最严格,所有脚本都必须签名

6. 打包成模块(终极复用方式)

目录结构:

MyTools/
│   MyTools.psd1
│   MyTools.psm1
└───Public
    │   Backup-Database.ps1
    │   Restore-Database.ps1
└───Private
    │   Write-Log.ps1

发布到公司内部 PowerShell Gallery:

Publish-Module -Path .\MyTools -Repository CompanyRepo -NuGetApiKey "xxx"

7. 一键部署脚本(推荐用这个模板)

# Deploy.ps1(双击即可部署)
$Source = "\\fileserver\scripts\Production"
$Target = "C:\Scripts"

if (!(Test-Path $Target)) { New-Item -Path $Target -ItemType Directory -Force }

Copy-Item "$Source\*.*" $Target -Recurse -Force

# 自动签名(如果有证书)
if ($cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert) {
    Get-ChildItem "$Target\*.ps1" | Set-AuthenticodeSignature -Cert $cert
}

Write-Host "部署完成!路径: $Target" -ForegroundColor Green

终极总结:企业级 PowerShell 脚本检查清单(发版前必过)

  • [ ] 加了 param 块和 [CmdletBinding()]
  • [ ] 所有参数都有类型和验证
  • [ ] 使用了 Write-Verbose / Write-Log,不用 Write-Host 刷屏
  • [ ] 所有外部命令都在 try/catch 里且加了 -ErrorAction Stop
  • [ ] 支持 -WhatIf 和 -Confirm
  • [ ] 脚本已数字签名
  • [ ] 写好了帮助注释(Get-Help 可显示)
  • [ ] 路径全部用 Resolve-Path / Join-Path
  • [ ] 已打包成模块或放在版本控制里
  • [ ] 在测试环境通过了 Pester 测试

把上面这些全部做到,你的 PowerShell 脚本就从“个人工具”进化成了“企业级自动化资产”。

需要我帮你把现有的脚本直接重构为企业级模板,或者帮你写 Pester 测试用例,随时贴代码,我直接给你改好!

文章已创建 2965

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部