PowerShell 实战的重点不是把语法背全,而是把一次性命令整理成可复用、可调试、可审计的自动化单元。函数、模块、错误处理和调试能力,决定脚本能不能从“自己机器上能跑”进入长期维护。

函数

函数定义和调用

使用 function 关键字定义可复用的代码块:

function Get-Greeting {
    Write-Output "Hello, World!"
}
 
Get-Greeting

函数参数

通过 param 块定义参数,支持默认值和类型约束:

function Get-Greeting {
    param (
        [string]$name = "World"
    )
    Write-Output "Hello, $name!"
}
 
Get-Greeting -name "Alice"

返回值

函数通过 return 或管道输出返回值:

function Add-Numbers {
    param ([int]$a, [int]$b)
    return $a + $b
}
 
$result = Add-Numbers -a 5 -b 3

高级函数

使用 [CmdletBinding()]ValueFromPipeline 支持管道输入:

function Get-Square {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [int]$number
    )
    process {
        return $number * $number
    }
}
 
1..5 | Get-Square

模块

模块概念

模块是将相关函数、变量和资源组织在一起的打包方式,便于重用和分发。模块文件以 .psm1 为扩展名。只要脚本开始被多个项目或多台机器复用,就应该考虑模块化。

创建和使用模块

  1. 创建 MyModule.psm1 文件:
function Get-Greeting {
    param ([string]$name = "World")
    Write-Output "Hello, $name!"
}
 
Export-ModuleMember -Function Get-Greeting
  1. 导入并使用:
# 确保模块路径在 $env:PSModulePath 中
 
Import-Module -Name "MyModule"
Get-Greeting -name "Alice"

Import-Module 和 Export-ModuleMember

  • Import-Module:加载模块使命令可用。
  • Export-ModuleMember:在 .psm1 中指定哪些函数对外暴露。

错误处理

try/catch/finally

try {
    $result = Get-Process -Name "Notepad"
    Write-Output "Process found: $($result.Name)"
} catch {
    Write-Output "An error occurred: $_"
} finally {
    Write-Output "Cleanup complete."
}

按异常类型捕获

try {
    $result = Get-Process -Name "Notepad"
} catch [System.Management.Automation.CommandNotFoundException] {
    Write-Output "Command not found: $_"
} catch [System.Exception] {
    Write-Output "General error: $_"
}

自定义错误处理

结合 -ErrorAction Stop 在函数中处理错误:

function Get-ProcessInfo {
    param ([string]$processName)
    try {
        $process = Get-Process -Name $processName -ErrorAction Stop
        Write-Output "CPU: $($process.CPU)"
    } catch {
        Write-Output "Process '$processName' not found."
    }
}

调试

断点调试

# 设置断点
 
Set-PSBreakpoint -Script "C:\Path\To\Script.ps1" -Line 5
 
# 查看断点
 
Get-PSBreakpoint
 
# 移除断点
 
Remove-PSBreakpoint -Id 0

调试命令

  • Get-PSBreakpoint:查看当前断点
  • Enable-PSBreakpoint / Disable-PSBreakpoint:启用/禁用断点
  • Get-PSCallStack:查看调用堆栈

Write-Debug 和 Write-Verbose

配合 [CmdletBinding()] 使用 -Debug-Verbose 开关:

function Test-Logging {
    [CmdletBinding()]
    param ([string]$message)
    Write-Debug "Debug: $message"
    Write-Verbose "Verbose: $message"
}
 
Test-Logging -message "Test" -Debug -Verbose

文件系统管理

基本操作

# 创建
 
New-Item -Path "C:\Example" -ItemType Directory
New-Item -Path "C:\Example\file.txt" -ItemType File
 
# 查看
 
Get-ChildItem -Path "C:\Example"
Get-ChildItem -Path "C:\Example" -Recurse       # 递归
Get-ChildItem -Path "C:\Example\*.txt"           # 通配符
 
# 读取和写入
 
Get-Content -Path "C:\Example\file.txt"
Set-Content -Path "C:\Example\file.txt" -Value "Hello"
Add-Content -Path "C:\Example\file.txt" -Value "Appended line"
 
# 复制、移动、删除
 
Copy-Item -Path "file.txt" -Destination "copy.txt"
Move-Item -Path "file.txt" -Destination "moved.txt"
Remove-Item -Path "C:\Example" -Recurse

压缩和解压

Compress-Archive -Path "C:\Example" -DestinationPath "archive.zip"
Expand-Archive -Path "archive.zip" -DestinationPath "C:\Unzipped"

进程与服务管理

进程管理

# 查看进程
 
Get-Process
Get-Process -Name "notepad"
 
# 启动和停止
 
Start-Process -FilePath "notepad.exe"
Stop-Process -Name "notepad"
 
# 详细信息
 
Get-Process -Name "notepad" | Select-Object Name, Id, CPU, WS

服务管理

# 查看服务
Get-Service
Get-Service -Name "wuauserv"
 
# 启动、停止、重启
Start-Service -Name "wuauserv"
Stop-Service -Name "wuauserv"
Restart-Service -Name "wuauserv"
 
# 设置启动类型
Set-Service -Name "wuauserv" -StartupType Automatic

自动化任务

计划任务

# 创建计划任务(每天 8:00 执行脚本)
 
$action   = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument '-NoProfile -File C:\Scripts\Backup.ps1'
$trigger  = New-ScheduledTaskTrigger -Daily -At 8am
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -TaskName "DailyBackup"
 
# 查看
 
Get-ScheduledTask -TaskName "DailyBackup"
 
# 修改触发器
 
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday,Wednesday,Friday -At 8am
Set-ScheduledTask -TaskName "DailyBackup" -Trigger $trigger
 
# 删除
 
Unregister-ScheduledTask -TaskName "DailyBackup" -Confirm:$false

自动化脚本示例

自动清理超过 30 天的日志文件:

$logPath  = "C:\Logs"
$daysOld  = 30
 
Get-ChildItem -Path $logPath -Filter *.log |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$daysOld) } |
    Remove-Item -Force
 
Write-Output "Old log files cleaned up."

使用原则

函数要像 cmdlet 一样可组合:参数明确、输出对象稳定、错误可捕获,才能放进管道和自动化流程。

模块化是复用边界:多个脚本共享的函数不要复制粘贴,放进模块并明确导出内容。

错误处理要区分终止和非终止错误:需要进入 catch 的命令常常要配合 -ErrorAction Stop

系统管理脚本默认有风险:删除文件、停止服务、注册计划任务前,优先提供 -WhatIf、日志和确认边界。

计划任务要可观察:自动运行的脚本必须有日志、退出码和失败通知,否则就是静默风险。