[Powershell 入门教程]第10天:综合项目实战与进阶

这是入门教程的最后一篇,希望读者可以实际用起来,实现逐步从入门到精通的全过程。

📅 第10天:综合项目实战与进阶

🔧 核心目标

将前9天所学(函数、REST API、作业、错误处理、JSON、模块化等)融会贯通,构建 可落地、可扩展、跨平台 的自动化工具。

✅ 适用环境:Windows / Linux / macOS(PowerShell 7+)

✅ 输出形式:独立脚本 + 模块化结构 + 用户友好交互


🎯 三大实战项目概览

项目 技术栈 应用场景
1. 自动化系统健康仪表盘 Get-Process, Get-Volume, Test-Connection, ConvertTo-Html 本地/远程服务器状态可视化
2. 跨平台服务检查器 Invoke-RestMethod, Start-ThreadJob, 参数验证 微服务/API 健康监测(HTTP/S)
3. RESTful 管理代理(Mock Agent) Register-ObjectEvent, New-PSSessionConfiguration, 自定义 REST 接口 安全接收外部指令并执行本地操作

🛠️ 项目1:自动化系统健康仪表盘

💡 需求

生成一个 HTML 报告,展示:

  • CPU 使用率 Top 5 进程
  • 内存使用率
  • 磁盘剩余空间(所有卷)
  • 网络连通性(到关键服务如 DNS、网关)
  • 最后更新时间

✅ 实现代码(Get-SystemHealthReport.ps1

cs 复制代码
function Get-SystemHealthReport {
    [CmdletBinding()]
    param(
        [string]$OutputPath = "./system_health_$(Get-Date -Format 'yyyyMMdd_HHmm').html"
    )

    # 获取数据
    $cpuTop = Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, CPU
    $memUsage = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)
    $totalMem = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2)
    $diskInfo = Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, 
        @{Name="FreeGB"; Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}},
        @{Name="TotalGB"; Expression={[math]::Round($_.Size / 1GB, 2)}}
    
    $networkTests = @(
        @{Target="8.8.8.8"; Status=(Test-Connection 8.8.8.8 -Count 1 -Quiet)}
        @{Target="gateway"; Status=(Test-Connection (Get-NetRoute 0.0.0.0).NextHop -Count 1 -Quiet -ErrorAction SilentlyContinue)}
    )

    # 构建 HTML
    $html = @"
<!DOCTYPE html>
<html>
<head><title>系统健康报告</title>
<style>
body { font-family: Arial; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.green { color: green; }
.red { color: red; }
</style>
</head>
<body>
<h1>📊 系统健康仪表盘</h1>
<p>生成时间: $(Get-Date)</p>

<h2>🔥 CPU Top 5 进程</h2>
$($cpuTop | ConvertTo-Html -Fragment)

<h2>🧠 内存使用</h2>
<p>总内存: ${totalMem} GB | 可用: ${memUsage} GB</p>

<h2>💾 磁盘空间</h2>
$($diskInfo | ConvertTo-Html -Fragment)

<h2>🌐 网络连通性</h2>
<table>
<tr><th>目标</th><th>状态</th></tr>
$(
    foreach ($test in $networkTests) {
        $color = if ($test.Status) { "green" } else { "red" }
        $statusText = if ($test.Status) { "✅ 在线" } else { "❌ 离线" }
        "<tr><td>$($test.Target)</td><td class='$color'>$statusText</td></tr>"
    }
)
</table>
</body>
</html>
"@

    $html | Out-File -FilePath $OutputPath -Encoding UTF8
    Write-Host "✅ 报告已生成: $OutputPath" -ForegroundColor Green
    if ($IsWindows) { Start-Process $OutputPath }
}

🔍 技术亮点

  • 跨平台兼容 :使用 Get-CimInstance(Windows)或可替换为 free(Linux)
  • HTML 内嵌 CSS:无需外部依赖,直接浏览器打开
  • 自动打开报告Start-Process(Windows)/ open(macOS)/ xdg-open(Linux)可进一步适配

🌐 项目2:跨平台服务检查器

💡 需求

并发检测多个 HTTP 服务状态(支持 Basic Auth、自定义 Header),输出表格并高亮异常。

✅ 实现代码(Test-ServiceHealth.ps1

cs 复制代码
function Test-ServiceHealth {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [hashtable[]]$Services,  # 示例: @{Url="https://api.example.com"; Auth="user:pass"}
        [int]$TimeoutSec = 10,
        [int]$MaxConcurrency = 5
    )

    # 安装 ThreadJob(如未安装)
    if (-not (Get-Module ThreadJob -ListAvailable)) {
        Install-Module ThreadJob -Scope CurrentUser -Force
    }

    $jobs = foreach ($svc in $Services) {
        Start-ThreadJob -ThrottleLimit $MaxConcurrency -ScriptBlock {
            param($url, $auth, $timeout)
            $headers = @{}
            if ($auth) {
                $bytes = [System.Text.Encoding]::ASCII.GetBytes($auth)
                $base64 = [Convert]::ToBase64String($bytes)
                $headers.Authorization = "Basic $base64"
            }

            $sw = [System.Diagnostics.Stopwatch]::StartNew()
            try {
                $response = Invoke-RestMethod -Uri $url -Headers $headers -TimeoutSec $timeout -UseBasicParsing
                $status = "OK"
                $statusCode = 200
            } catch {
                $status = "FAIL"
                $statusCode = $_.Exception.Response?.StatusCode?.value__ -as [int] -or 0
            }
            $sw.Stop()

            [PSCustomObject]@{
                Service = $url
                Status  = $status
                Code    = $statusCode
                Latency = $sw.ElapsedMilliseconds
                Time    = Get-Date
            }
        } -ArgumentList $svc.Url, $svc.Auth, $TimeoutSec
    }

    $results = $jobs | Wait-Job | Receive-Job
    $jobs | Remove-Job

    # 彩色输出
    $results | ForEach-Object {
        $color = if ($_.Status -eq "OK") { "Green" } else { "Red" }
        Write-Host "$($_.Service) | $($_.Status) | Code: $($_.Code) | Latency: $($_.Latency)ms" -ForegroundColor $color
    }

    return $results
}

# 使用示例
$myServices = @(
    @{Url = "https://httpbin.org/status/200"},
    @{Url = "https://httpbin.org/status/500"},
    @{Url = "https://api.github.com/rate_limit"; Auth = "user:token"} # 如需认证
)

Test-ServiceHealth -Services $myServices -MaxConcurrency 3

🔍 技术亮点

  • Start-ThreadJob:轻量级并发,避免传统 Job 开销
  • Basic Auth 支持:动态构造 Authorization Header
  • 结构化输出 :返回对象数组,便于后续 Export-Csv 或告警集成

🤖 项目3:RESTful 管理代理(安全执行本地命令)

⚠️ 仅限受控内网环境!需严格权限控制

💡 需求

启动一个本地 HTTP 服务,接收 JSON 指令(如 {"action": "restart-service", "service": "spooler"}),执行对应 PowerShell 命令并返回结果。

✅ 实现思路(简化版,基于 HttpListener

cs 复制代码
# rest-agent.ps1
function Start-ManagementAgent {
    param([int]$Port = 8080)

    $listener = New-Object System.Net.HttpListener
    $listener.Prefixes.Add("http://localhost:$Port/")
    $listener.Start()
    Write-Host "🚀 管理代理已启动: http://localhost:$Port/" -ForegroundColor Cyan

    while ($listener.IsListening) {
        $context = $listener.GetContext()
        $request = $context.Request
        $response = $context.Response

        if ($request.HttpMethod -ne "POST") {
            $msg = "仅支持 POST"
            $buffer = [System.Text.Encoding]::UTF8.GetBytes($msg)
            $response.StatusCode = 405
            $response.OutputStream.Write($buffer, 0, $buffer.Length)
            $response.Close()
            continue
        }

        # 读取请求体
        $reader = New-Object System.IO.StreamReader($request.InputStream)
        $rawBody = $reader.ReadToEnd()
        $reader.Dispose()

        try {
            $payload = $rawBody | ConvertFrom-Json
            $action = $payload.action

            switch ($action) {
                "get-process" {
                    $result = Get-Process | Select-Object Name, Id, CPU | ConvertTo-Json
                }
                "restart-service" {
                    $svc = $payload.service
                    Restart-Service $svc -PassThru | Out-Null
                    $result = @{ status = "success"; service = $svc } | ConvertTo-Json
                }
                default {
                    throw "不支持的操作: $action"
                }
            }

            $buffer = [System.Text.Encoding]::UTF8.GetBytes($result)
            $response.ContentType = "application/json"
            $response.StatusCode = 200
        } catch {
            $err = @{ error = $_.Exception.Message } | ConvertTo-Json
            $buffer = [System.Text.Encoding]::UTF8.GetBytes($err)
            $response.StatusCode = 500
        }

        $response.OutputStream.Write($buffer, 0, $buffer.Length)
        $response.Close()
    }
}

# 启动代理(后台运行)
Start-ManagementAgent -Port 8080

🔒 安全加固建议(生产环境必须):

  1. 绑定到 127.0.0.1(禁止外网访问)
  2. 添加 API Token 认证 (检查 Header 中 X-API-Key
  3. 白名单操作(只允许预定义的 action)
  4. 以最小权限账户运行

🧪 测试命令(另一终端):

cs 复制代码
# 重启打印服务
$body = @{ action = "restart-service"; service = "spooler" } | ConvertTo-Json
Invoke-RestMethod -Uri "http://localhost:8080/" -Method Post -Body $body -ContentType "application/json"

# 获取进程列表
Invoke-RestMethod -Uri "http://localhost:8080/" -Method Post -Body '{"action":"get-process"}' -ContentType "application/json"

🧠 第10天能力升华

能力维度 体现
工程化思维 模块化、参数化、错误隔离
跨平台意识 避免 Windows 专属 Cmdlet(如用 Get-CimInstance → 可替换)
安全第一 输入验证、最小权限、网络隔离
用户体验 彩色输出、HTML 报告、进度反馈
可扩展性 函数设计支持管道、导出 CSV、集成监控系统

🚀 课后挑战(选做)

  1. 仪表盘 改为 Web 服务(用 Start-ManagementAgent 返回 HTML)
  2. 服务检查器 添加 Slack/邮件告警(当状态 ≠ 200)
  3. 管理代理 封装为 Windows Service(使用 nssm.exe
相关推荐
課代表17 小时前
bat 批处理文件中 PowerShell 命令换行问题
符号·参数·powershell·批处理·换行·续行符·管道符
龙泉寺天下行走7 天前
[powershell 入门教程]第9天:PowerShell 安全、代码签名与企业部署
安全·powershell
課代表8 天前
PowerShell 字符转 UniCode 编码
字符编码·类型转换·unicode·powershell·批处理·转义·[char]
fengyehongWorld10 天前
Powershell 实现系统静音
powershell
艾莉丝努力练剑10 天前
【Git:企业级开发模型】Git企业级Git工作流实战:基于Git Flow的分支模型与开发流程
服务器·git·ubuntu·gitee·centos·powershell·企业级开发模型
charlee4418 天前
Git使用经验总结8-Git仓库历史记录清除
git·powershell·敏感信息·仓库重置·历史重写
tq10861 个月前
一个简单的 PowerShell REPL 脚本
powershell
guojikun2 个月前
一键配置 Web 前端开发环境(PowerShell 自动化脚本)
windows·web前端·powershell
WarPigs2 个月前
Powershell笔记
脚本·powershell