PowerShell 脚本基础:Windows 自动化管理

FreeGuideOnline 最新 2026-06-13

PowerShell 脚本基础:Windows 自动化管理

前言

PowerShell 是微软推出的跨平台任务自动化解决方案,集命令行 Shell、脚本语言和配置管理框架于一体。在 Windows 系统中,它不仅是系统管理员的利器,也正在成为每一位高效用户的标准工具。本教程将带你从零开始,掌握使用 PowerShell 脚本实现 Windows 自动化管理的核心知识。无论你是否有编程经验,都可以跟随本文完成从环境搭建到编写实用自动化脚本的过程。

第1章:认识 PowerShell 环境

1.1 什么是 PowerShell

PowerShell 基于 .NET 框架,提供了一种面向对象的命令行体验。与传统的 cmd.exe 不同,它处理的不是文本流,而是结构化的对象。这意味着你可以直接访问系统组件、注册表、文件系统、进程等,并以一致的方式操作它们。常见的版本有 Windows PowerShell 5.1 和跨平台的 PowerShell 7+,本教程以 PowerShell 5.1 及以上版本为基准。

1.2 启动 PowerShell 与执行策略

  • 启动方式:在开始菜单搜索“PowerShell”,右键选择“以管理员身份运行”以获得最高权限。
  • 执行策略:为防止恶意脚本运行,PowerShell 默认限制脚本执行。使用管理员权限打开 PowerShell,输入以下命令查看当前策略:
    Get-ExecutionPolicy
    
    若显示 Restricted,你需要将其更改为 RemoteSigned 以允许运行本地脚本:
    Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
    
    该命令将当前用户的执行策略设置为允许运行本地创建的脚本,远程下载的脚本必须经过数字签名。

1.3 集成脚本环境 (ISE) 与 VS Code

  • Windows PowerShell ISE:内置的脚本编辑与调试工具,支持语法高亮、多选项卡和命令面板。
  • Visual Studio Code + PowerShell 扩展:更现代化的选择,具备智能感知、Git 集成和丰富的调试能力。推荐初学者从 ISE 开始,后续迁移至 VS Code。

第2章:基础命令与对象管道

2.1 Cmdlet 命名规则

PowerShell 命令称为 Cmdlet(读作 "command-let"),采用“动词-名词”结构,例如 Get-ProcessStop-Service。常用动词有:

  • Get:获取信息
  • Set:设置配置
  • Start / Stop:启动/停止服务或进程
  • New / Remove:创建/删除对象
  • Out:输出到文件或打印机

通过 Get-Command 可以探索可用命令:

Get-Command -Noun Process    # 查找与进程相关的所有命令

2.2 面向对象的管道

管道符 | 将一个命令的输出作为对象传递给下一个命令,无需像 Linux Shell 那样解析文本。

Get-Process | Where-Object { $_.CPU -gt 10 } | Sort-Object CPU -Descending

解释:获取所有进程,筛选 CPU 时间大于 10 秒的进程,然后按 CPU 时间降序排序。$_ 代表管道中的当前对象。

2.3 获取帮助与发现参数

  • Get-Help Get-Process -Full:查看详细帮助,包含参数说明和示例。
  • Get-Command -ParameterName ComputerName:查找所有支持 -ComputerName 参数的命令。
  • Get-Member:探索对象成员(属性和方法)。例如:
    Get-Process | Get-Member
    
    你会看到每个进程对象拥有的属性,如 NameIdWorkingSet 等。

第3章:变量、数据类型与运算符

3.1 变量的使用

变量名前加 $ 符号,不需要显式声明类型。PowerShell 会自动推断类型。

$processName = "notepad"
$count = 5
$isRunning = $true

双引号字符串会解析变量和转义字符,单引号字符串则被视为纯文字:

$name = "World"
Write-Output "Hello, $name"      # 输出 Hello, World
Write-Output 'Hello, $name'      # 输出 Hello, $name

3.2 常用数据类型与转换

  • 数组:$arr = @(1, 2, 3) 或使用 @() 创建空数组。
  • 哈希表:$hash = @{ Key1 = "Value1"; Key2 = 2 },常用于参数集合。
  • 自定义对象:
    $obj = [PSCustomObject]@{
        Name = "ServerA"
        Status = "Online"
    }
    
  • 类型强转:[int]"42" 可将字符串转换为整数。

3.3 运算符一览

类型 运算符 示例
算术 + - * / % 5 % 2 结果为 1
比较 -eq -ne -gt -lt -ge -le $a -eq $b
逻辑 -and -or -not $x -gt 0 -and $y -lt 10
字符串匹配 -like -notlike -match -replace "PowerShell" -like "Power*"$true
包含 -contains -notcontains $arr -contains 2
类型判断 -is $a -is [int]

第4章:脚本结构与流控制

4.1 编写和运行脚本

将 PowerShell 命令保存为 .ps1 文件,然后通过路径调用。例如,创建 Backup.ps1

# 备份当前用户文档到 D 盘
$source = "$env:USERPROFILE\Documents"
$dest = "D:\Backup\Documents_$(Get-Date -Format 'yyyyMMdd')"
Copy-Item -Path $source -Destination $dest -Recurse
Write-Host "备份完成:$dest"

运行方式:在脚本所在目录执行 .\Backup.ps1。注意需提前设置合适的执行策略。

4.2 条件判断:if / else

$service = Get-Service -Name "Spooler"
if ($service.Status -eq 'Running') {
    Write-Host "打印服务正在运行"
} elseif ($service.Status -eq 'Stopped') {
    Write-Host "打印服务已停止,尝试启动..."
    Start-Service -Name "Spooler" -Verbose
} else {
    Write-Host "未知状态:$($service.Status)"
}

4.3 循环结构

  • Foreach:遍历集合中的每个元素。
    $services = Get-Service | Where-Object { $_.Status -eq 'Stopped' }
    foreach ($svc in $services) {
        Write-Host "尝试启动 $($svc.Name)..."
        Start-Service $svc.Name -ErrorAction SilentlyContinue
    }
    
  • For:传统计数循环。
    for ($i = 1; $i -le 5; $i++) {
        Write-Host "测试连接第 $i 次"
        Test-Connection -ComputerName "192.168.1.$i" -Count 1 -Quiet
    }
    
  • While / Do-While:条件循环。
    $count = 0
    while ($count -lt 3) {
        Write-Host "等待第 $count 次"
        Start-Sleep -Seconds 1
        $count++
    }
    

4.4 错误处理:Try/Catch/Finally

PowerShell 支持结构化异常处理,需设置 -ErrorAction Stop 将非终止错误转换为终止错误,才能被 Catch 捕获。

try {
    $files = Get-ChildItem -Path "C:\InvalidPath" -ErrorAction Stop
} catch {
    Write-Warning "捕获到错误:$($_.Exception.Message)"
} finally {
    Write-Host "清理代码在此执行"
}

常见 -ErrorAction 参数值:Continue(默认)、SilentlyContinueStopInquire

第5章:自动化管理实战案例

5.1 批量文件重命名

需求:将某个文件夹中的所有 .log 文件添加创建日期前缀。

$folderPath = "C:\Logs"
Get-ChildItem -Path $folderPath -Filter "*.log" | ForEach-Object {
    $newName = "{0:yyyyMMdd}_{1}" -f $_.CreationTime, $_.Name
    Rename-Item -Path $_.FullName -NewName $newName
}
Write-Host "所有 .log 文件已重命名。"

其中 -f 是格式化操作符,{0}{1} 分别占位。

5.2 系统信息收集与HTML报告

需求:收集计算机名、操作系统版本、内存总量及前5个高CPU进程,生成HTML报告。

$computer = $env:COMPUTERNAME
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$memGB = [math]::Round($os.TotalVisibleMemorySize/1MB, 2)
$topProcs = Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 |
            Select-Object Name, CPU, WorkingSet

# 构建HTML片段
$html = @"
<html><body>
<h2>系统报告:$computer</h2>
<p>操作系统:$($os.Caption) ($($os.Version))</p>
<p>总内存:$memGB GB</p>
<h3>Top 5 按CPU使用排序的进程</h3>
$($topProcs | ConvertTo-Html -Fragment)
</body></html>
"@

$reportPath = "C:\Reports\SystemReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
$html | Out-File -FilePath $reportPath
Invoke-Item $reportPath   # 自动打开报告

ConvertTo-Html 可将对象转换为HTML表格,适合快速生成报告。

5.3 远程服务监控与自动恢复

需求:检查远程计算机的指定服务是否运行,若停止则尝试启动并发送邮件通知。

$servers = @("Server01", "Server02")
$serviceName = "W3SVC"  # IIS服务
$smtpServer = "smtp.example.com"
$from = "alert@example.com"
$to = "admin@example.com"

foreach ($server in $servers) {
    try {
        $svc = Get-Service -Name $serviceName -ComputerName $server -ErrorAction Stop
        if ($svc.Status -ne 'Running') {
            Write-Host "在 $server 上 $serviceName 未运行,尝试启动..."
            Start-Service -InputObject $svc -ErrorAction Stop
            $body = "服务 $serviceName 已在服务器 $server 上自动恢复启动。"
            Send-MailMessage -SmtpServer $smtpServer -From $from -To $to -Subject "服务恢复通知" -Body $body
        }
    } catch {
        $errorMsg = "无法连接 $server 或操作失败:$_"
        Write-Warning $errorMsg
        Send-MailMessage -SmtpServer $smtpServer -From $from -To $to -Subject "服务监控失败" -Body $errorMsg
    }
}

注意:Send-MailMessage 在较新版本中已弃用,生产环境中建议使用 System.Net.Mail.SmtpClient 类或第三方模块。

第6章:编写健壮的脚本与最佳实践

6.1 使用参数提高脚本灵活性

将脚本中的固定值替换为参数,可在运行时传入不同值:

param(
    [Parameter(Mandatory=$true)]
    [string]$SourcePath,

    [Parameter(Mandatory=$false)]
    [string]$DestinationPath = "C:\Backup"
)
if (-not (Test-Path $DestinationPath)) {
    New-Item -ItemType Directory -Path $DestinationPath
}
Copy-Item -Path $SourcePath -Destination $DestinationPath -Recurse

调用:.\Backup.ps1 -SourcePath "C:\Data" -DestinationPath "D:\Backup"

6.2 注释与文档

  • 单行注释以 # 开头。
  • 注释块使用 <# ... #>
  • 利用基于注释的帮助,将帮助信息嵌入脚本开头:
    <#
    .SYNOPSIS
        执行文件夹备份。
    .DESCRIPTION
        将指定源文件夹复制到目标位置,如果目标不存在则自动创建。
    .PARAMETER SourcePath
        要备份的源文件夹路径。
    .EXAMPLE
        .\Backup.ps1 -SourcePath "C:\MyData"
    #>
    
    这样,用户通过 Get-Help .\Backup.ps1 -Full 即可看到详细说明。

6.3 避免硬编码和模块化

  • 将通用功能封装为函数,最终形成模块(.psm1 文件),便于复用。
  • 使用环境变量(如 $env:USERPROFILE)和自动变量(如 $PSScriptRoot 获取脚本所在目录)增强可移植性。
  • 大量安装部署场景推荐使用 PowerShellGet 组织脚本模块。

第7章:调试与故障排查

7.1 基本调试方法

  • 在 ISE 或 VS Code 中设置断点:按 F9 切换断点,F5 运行脚本,F11 逐过程调试。
  • 使用 Set-PSBreakpoint 命令行设置变量断点:
    Set-PSBreakpoint -Script ".\script.ps1" -Variable "counter" -Mode Write
    
    $counter 变量被写入时脚本中断。
  • Write-Debug$DebugPreference:在脚本中加入 Write-Debug "当前值:$value",运行时添加 -Debug 开关即可查看这些调试信息。

7.2 常用诊断命令

  • Get-PSCallStack:显示当前调用堆栈,适用于嵌套函数调试。
  • Trace-Command:跟踪特定组件的内部操作(高级用法)。
  • 使用 $Error 自动变量查看最近发生的错误记录。$Error[0] 是最近一条错误,$Error[0] | Format-List * -Force 查看完整详情。

8. 进阶学习路径与资源

掌握上述基础后,你可以向以下方向深入:

  • Desired State Configuration (DSC):声明式配置管理,保证服务器配置一致。
  • PowerShell Remoting (WinRM):使用 Invoke-CommandEnter-PSSession 管理批量远程节点。
  • .NET 互操作:在 PowerShell 中直接调用 .NET 类库,例如 [System.IO.File]::ReadAllText()
  • 持续集成与自动化:将脚本集成到 Azure DevOps、Jenkins 或 GitHub Actions 中。

推荐微软官方文档 PowerShell 文档 和社区书籍《Learn PowerShell in a Month of Lunches》作为延伸阅读。


总结:通过本篇教程,你已经了解了 PowerShell 的基本环境、对象管道的思维模式、脚本编写、错误处理以及多个务实的自动化案例。Windows 自动化管理并非高不可攀,从编写你的第一个脚本开始,逐步将日常重复任务交给 PowerShell,你将体验到效率的飞跃。