[Powershell入门教程]第4天:模块、脚本编写、错误处理与 .NET 集成

第4天:模块、脚本编写、错误处理与 .NET 集成

🎯 学习目标

  • 掌握 PowerShell 脚本(.ps1)的结构与最佳实践
  • 理解模块(Module)的作用,并能创建和导入自定义模块
  • 熟练使用 try/catch/finally 进行结构化错误处理
  • 直接调用 .NET 类库(如 System.IO, System.Net 等)完成高级任务

一、PowerShell 脚本编写(.ps1 文件)

1. 脚本基本结构

一个良好的脚本应包含:

  • 注释说明(用途、作者、参数)
  • 参数声明(param 块)
  • 错误处理($ErrorActionPreferencetry/catch
  • 主逻辑
  • 清理或输出
bash 复制代码
# Get-DiskUsage.ps1
<#
.SYNOPSIS
    获取指定目录的磁盘使用情况。
.DESCRIPTION
    计算目录下所有文件总大小,支持递归。
.PARAMETER Path
    目标路径,默认为当前目录。
.EXAMPLE
    .\Get-DiskUsage.ps1 -Path C:\Temp
#>

param(
    [string]$Path = "."
)

if (-not (Test-Path $Path)) {
    throw "路径不存在: $Path"
}

$totalBytes = (Get-ChildItem -Path $Path -Recurse -File | Measure-Object -Property Length -Sum).Sum
"{0:N2} MB" -f ($totalBytes / 1MB)

💡 使用方式:

bash 复制代码
.\Get-DiskUsage.ps1 -Path C:\Windows

2. 脚本执行方式回顾

方式 命令 说明
当前作用域运行 . .\script.ps1 变量/函数留在当前会话(点源执行)
子作用域运行 .\script.ps1 执行完后环境不保留
绕过策略运行 PowerShell -ExecutionPolicy Bypass -File script.ps1 适合自动化

二、模块(Modules)------组织可重用代码

1. 什么是模块?

模块是 PowerShell 中用于封装函数、变量、别名等的单元,便于分发和复用。

内置模块示例:

bash 复制代码
Get-Module -ListAvailable  # 查看所有可用模块
Import-Module ActiveDirectory  # 导入 AD 模块(需安装)

2. 创建自定义模块

步骤1:创建模块目录
bash 复制代码
C:\Users\<username>\Documents\Documents\WindowsPowerShell\PowerShell\Modules\MyTools\
└── MyTools.psm1   ← 模块主文件

⚠️ 路径必须在 $env:PSModulePath 中(用户模块默认在此)

⚠️ 可能次路径不存在,需手动建立

步骤2:编写 MyTools.psm1
bash 复制代码
# MyTools.psm1
function Get-Uptime {
    $os = Get-CimInstance Win32_OperatingSystem
    (Get-Date) - $os.LastBootUpTime
}

function Test-Port {
    param([string]$ComputerName, [int]$Port)
    try {
        $tcp = New-Object System.Net.Sockets.TcpClient
        $tcp.Connect($ComputerName, $Port)
        $tcp.Connected
        $tcp.Close()
    } catch {
        $false
    }
}

Export-ModuleMember -Function Get-Uptime, Test-Port
步骤3:导入并使用
bash 复制代码
Import-Module MyTools
Get-Uptime
Test-Port -ComputerName "baidu.com" -Port 80

✅ 优势:函数自动加载,命名空间清晰,易于共享。


三、错误处理:try / catch / finally

PowerShell 支持结构化异常处理,但需注意:

  • 仅对"终止性错误"(Terminating Errors)生效
  • 默认很多命令产生的是"非终止错误"(如 Get-Item NoSuchFile

1. 强制将错误转为终止错误

使用 -ErrorAction Stop

bash 复制代码
try {
    Get-Item "C:\NonExistentFile.txt" -ErrorAction Stop
} catch {
    Write-Host "捕获到错误: $($_.Exception.Message)" -ForegroundColor Red
} finally {
    Write-Host "清理操作(无论成功与否都会执行)"
}

2. 捕获特定异常类型(.NET 集成)

你可以根据 .NET 异常类型进行精细处理:

bash 复制代码
try {
    [System.IO.File]::ReadAllText("C:\Protected\file.txt")
} catch [System.UnauthorizedAccessException] {
    Write-Host "权限不足!" -ForegroundColor Yellow
} catch [System.IO.FileNotFoundException] {
    Write-Host "文件未找到!" -ForegroundColor Cyan
} catch {
    Write-Host "未知错误: $($_.Exception.GetType().FullName)"
}

🔍 提示:通过 $_.Exception.GetType().FullName 查看具体异常类型。


四、PowerShell 与 .NET 深度集成(核心优势!)

PowerShell 基于 .NET(Windows 上是 .NET Framework/.NET,跨平台是 .NET Core),可直接调用任何 .NET 类。

1. 调用静态方法

bash 复制代码
# 获取当前时间(等价于 Get-Date)
[System.DateTime]::Now

# 生成 GUID
[System.Guid]::NewGuid()

# 环境信息
[System.Environment]::OSVersion
[System.Environment]::GetFolderPath("Desktop")

2. 创建 .NET 对象实例

bash 复制代码
# 创建 WebClient(已过时,推荐使用 Invoke-WebRequest)
$client = New-Object System.Net.WebClient
$content = $client.DownloadString("https://httpbin.org/ip")
$client.Dispose()  # 释放资源

✅ 更现代的方式(PowerShell 5+):

bash 复制代码
Invoke-RestMethod https://httpbin.org/ip

3. 使用 .NET 枚举

bash 复制代码
# 文件属性
$file = Get-Item .\test.txt
$file.Attributes -band [System.IO.FileAttributes]::Hidden

4. 调用 .NET 方法处理字符串/数学

bash 复制代码
# 字符串操作(比 PowerShell 内置更强大)
[System.String]::IsNullOrWhiteSpace("   ")  # True

# 数学计算
[Math]::Round(3.14159, 2)  # 3.14
[Math]::Pow(2, 10)         # 1024

5. 实战:用 .NET 发送邮件(无需 Outlook)

bash 复制代码
$smtp = New-Object Net.Mail.SmtpClient("smtp.example.com", 587)
$smtp.EnableSsl = $true
$smtp.Credentials = [Net.NetworkCredential]::new("user@example.com", "password")

$mail = [Net.Mail.MailMessage]::new("from@example.com", "to@example.com", "主题", "正文")
$smtp.Send($mail)
$smtp.Dispose()

⚠️ 注意:生产环境建议使用安全凭据(如 $PSCredential)。


五、动手实践:综合项目

项目:编写一个带错误处理的"网站健康检查"脚本

bash 复制代码
# HealthCheck.ps1
param(
    [string[]]$Urls = @("https://baidu.com", "https://github.com")
)

foreach ($url in $Urls) {
    try {
        Write-Host "正在检查: $url" -ForegroundColor Green
        $response = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
        if ($response.StatusCode -eq 200) {
            Write-Host "✅ 正常 (状态码: $($response.StatusCode))"
        } else {
            Write-Host "⚠️ 异常状态码: $($response.StatusCode)" -ForegroundColor Yellow
        }
    } catch {
        $ex = $_.Exception
        if ($ex -is [System.Net.WebException]) {
            Write-Host "❌ 网络错误: $($ex.Message)" -ForegroundColor Red
        } else {
            Write-Host "💥 未知错误: $($ex.Message)" -ForegroundColor Magenta
        }
    }
}

运行:

bash 复制代码
.\HealthCheck.ps1 -Urls "https://baidu.com", "https://nonexistent.fake"

六、今日重点总结

  • ✅ 脚本应结构清晰,包含参数、注释和错误处理
  • ✅ 模块(.psm1)是组织可重用函数的最佳方式
  • try/catch 需配合 -ErrorAction Stop 或 .NET 异常使用
  • ✅ PowerShell 是 .NET 的"脚本前端",可直接调用任何 .NET 类库
  • ✅ 利用 [System.xxx]New-Object 解锁高级功能(网络、文件、加密等)

📚 参考资料(Microsoft Learn)

  • About Modules
  • About Try Catch Finally
  • Calling .NET Methods
  • .NET API Browser

🏁 课后作业

  1. 创建一个名为 MathUtils 的模块,包含两个函数:Convert-Temperature(℃↔℉)和 Get-Factorial(阶乘,用递归或 .NET BigInteger)。
  2. 编写脚本:尝试读取一个受保护的系统文件(如 C:\Windows\System32\config\SAM),使用 try/catch 捕获 UnauthorizedAccessException 并友好提示。
  3. 使用 .NET 的 System.IO.Compression.ZipFile 类,编写一个函数 Compress-Folder,将指定文件夹压缩为 ZIP。
相关推荐
aniden2 小时前
Swagger从入门到实战
java·开发语言·spring
晴天丨2 小时前
Vite:下一代前端构建工具深度解析与实践指南
前端
泥嚎泥嚎2 小时前
【Android】给App添加启动画面——SplashScreen
android·java
多来哈米2 小时前
Jenkins配置vue前端项目(最简单的操作)
运维·前端·jenkins
一只叁木Meow2 小时前
Vue scoped CSS 与 Element Plus Drawer 样式失效问题深度解析
前端
用户92426257007312 小时前
Vue 学习笔记:组件通信(Props / 自定义事件)与插槽(Slot)全解析
前端
Java天梯之路2 小时前
09 Java 异常处理
java·后端
玖剹2 小时前
多线程编程:从日志到单例模式全解析
java·linux·c语言·c++·ubuntu·单例模式·策略模式
UIUV2 小时前
Ajax 数据请求学习笔记
前端·javascript·代码规范