适用于 PowerShell 5.1 及以上版本(Windows)
运维人员经常需要将系统指标、日志统计等数据以图表形式呈现,用于周报、容量规划或故障分析。虽然 Excel 和 Grafana 是常见的可视化工具,但 PowerShell 本身也具备生成图表的能力——通过 .NET 的 System.Windows.Forms.DataVisualization 命名空间或导出为 HTML/CSV 交由外部工具渲染,都能快速将数据转化为直观的图形。
本文将介绍如何使用 PowerShell 生成柱状图、折线图、饼图,以及如何将图表嵌入自动化报告。
使用 .NET Chart 控件生成图表 Windows 上的 PowerShell 可以直接调用 .NET 的 Chart 控件生成图片。这个控件功能丰富,支持柱状图、折线图、饼图、散点图等多种图表类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 Add-Type -AssemblyName System.Windows.FormsAdd-Type -AssemblyName System.Windows.Forms.DataVisualization$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart$chart .Width = 800 $chart .Height = 500 $chart .BackColor = [System.Drawing.Color ]::White$chartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea$chartArea .Name = "MainArea" $chartArea .AxisX.Title = "服务器" $chartArea .AxisY.Title = "CPU 使用率 (%)" $chartArea .AxisY.Minimum = 0 $chartArea .AxisY.Maximum = 100 $chart .ChartAreas.Add($chartArea )$servers = @ ( @ { Name = 'WEB-01' ; CPU = 72.5 } @ { Name = 'WEB-02' ; CPU = 45.3 } @ { Name = 'DB-01' ; CPU = 89.1 } @ { Name = 'DB-02' ; CPU = 63.8 } @ { Name = 'APP-01' ; CPU = 34.2 } @ { Name = 'APP-02' ; CPU = 55.7 } ) $series = New-Object System.Windows.Forms.DataVisualization.Charting.Series$series .Name = "CPU使用率" $series .ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType ]::Column$series .Color = [System.Drawing.Color ]::SteelBlue$series .IsValueShownAsLabel = $true foreach ($srv in $servers ) { $series .Points.AddXY($srv .Name, $srv .CPU) | Out-Null } $chart .Series.Add($series )$title = New-Object System.Windows.Forms.DataVisualization.Charting.Title$title .Text = "服务器 CPU 使用率监控" $title .Font = New-Object System.Drawing.Font("Microsoft YaHei" , 14 , [System.Drawing.FontStyle ]::Bold)$chart .Titles.Add($title )$outputPath = "C:\Reports\cpu_usage.png" $chart .SaveImage($outputPath , [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat ]::Png)Write-Host "图表已保存到:$outputPath " -ForegroundColor Green
执行结果示例:
1 图表已保存到:C :\Reports \cpu_usage.png
生成折线图展示趋势 折线图适合展示时间序列数据,如 CPU 使用率趋势、内存变化等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Add-Type -AssemblyName System.Windows.Forms.DataVisualization$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart$chart .Width = 900 $chart .Height = 500 $chart .BackColor = [System.Drawing.Color ]::White$chartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea$chartArea .Name = "TrendArea" $chartArea .AxisX.Title = "时间" $chartArea .AxisY.Title = "使用率 (%)" $chartArea .AxisY.Minimum = 0 $chartArea .AxisY.Maximum = 100 $chart .ChartAreas.Add($chartArea )$hours = 0 ..23 $memUsage = @ (42 , 40 , 38 , 35 , 33 , 32 , 45 , 58 , 67 , 72 , 75 , 73 , 70 , 68 , 71 , 74 , 78 , 76 , 65 , 58 , 52 , 48 , 45 , 43 ) $series = New-Object System.Windows.Forms.DataVisualization.Charting.Series$series .Name = "内存使用率" $series .ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType ]::Line$series .Color = [System.Drawing.Color ]::OrangeRed$series .BorderWidth = 3 $series .IsValueShownAsLabel = $false for ($i = 0 ; $i -lt $hours .Count; $i ++) { $series .Points.AddXY("$ ($hours [$i ]):00" , $memUsage [$i ]) | Out-Null } $chart .Series.Add($series )$title = New-Object System.Windows.Forms.DataVisualization.Charting.Title$title .Text = "24 小时内存使用率趋势" $title .Font = New-Object System.Drawing.Font("Microsoft YaHei" , 14 , [System.Drawing.FontStyle ]::Bold)$chart .Titles.Add($title )$chart .SaveImage("C:\Reports\memory_trend.png" , "Png" )Write-Host "折线图已保存" -ForegroundColor Green
执行结果示例:
生成饼图展示占比 饼图适合展示各部分占总体的比例,如磁盘空间分配、服务状态分布等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 Add-Type -AssemblyName System.Windows.Forms.DataVisualization$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart$chart .Width = 700 $chart .Height = 500 $chart .BackColor = [System.Drawing.Color ]::White$chartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea$chartArea .Name = "PieArea" $chart .ChartAreas.Add($chartArea )$diskData = @ ( @ { Label = '系统文件' ; Size = 85.2 } @ { Label = '应用程序' ; Size = 120.5 } @ { Label = '用户数据' ; Size = 156.3 } @ { Label = '日志文件' ; Size = 42.8 } @ { Label = '可用空间' ; Size = 191.6 } ) $series = New-Object System.Windows.Forms.DataVisualization.Charting.Series$series .Name = "磁盘空间" $series .ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType ]::Pie$series .IsValueShownAsLabel = $true $series .LabelFormat = "{0} GB" $colors = @ ( [System.Drawing.Color ]::SteelBlue, [System.Drawing.Color ]::Orange, [System.Drawing.Color ]::Green, [System.Drawing.Color ]::Red, [System.Drawing.Color ]::LightGray ) for ($i = 0 ; $i -lt $diskData .Count; $i ++) { $pointIndex = $series .Points.AddXY($diskData [$i ].Label, $diskData [$i ].Size) $series .Points[$pointIndex ].Color = $colors [$i ] } $chart .Series.Add($series )$title = New-Object System.Windows.Forms.DataVisualization.Charting.Title$title .Text = "磁盘空间分配(C盘 596 GB)" $title .Font = New-Object System.Drawing.Font("Microsoft YaHei" , 14 , [System.Drawing.FontStyle ]::Bold)$chart .Titles.Add($title )$legend = New-Object System.Windows.Forms.DataVisualization.Charting.Legend$legend .Name = "Default" $chart .Legends.Add($legend )$series .Legend = "Default" $chart .SaveImage("C:\Reports\disk_usage_pie.png" , "Png" )Write-Host "饼图已保存" -ForegroundColor Green
执行结果示例:
生成 HTML 报告 在实际运维中,将数据导出为 HTML 格式更便于分享和查看。结合 Chart.js 或简单的 HTML 表格,可以创建美观的自动化报告:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 function New-ServerHealthReport { [CmdletBinding ()] param ( [string ]$OutputPath = "C:\Reports\ServerHealth.html" ) $os = Get-CimInstance -ClassName Win32_OperatingSystem $cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object -First 1 $disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" $topProcesses = Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 Name, Id, @ {N='内存MB' ; E={[math ]::Round($_ .WorkingSet64/1 MB,1 )}} $totalRam = [math ]::Round($os .TotalVisibleMemorySize / 1 MB, 2 ) $freeRam = [math ]::Round($os .FreePhysicalMemory / 1 MB, 2 ) $usedRamPct = [math ]::Round(($totalRam - $freeRam ) / $totalRam * 100 , 1 ) $html = @" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>服务器健康报告 - $ ($os .CSName)</title> <style> body { font-family: 'Segoe UI', sans-serif; margin: 20px; background: #f5f5f5; } .card { background: white; border-radius: 8px; padding: 20px; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } h1 { color: #333; } h2 { color: #555; border-bottom: 2px solid #0078d4; padding-bottom: 8px; } table { width: 100%; border-collapse: collapse; margin: 10px 0; } th { background: #0078d4; color: white; padding: 10px; text-align: left; } td { padding: 8px 10px; border-bottom: 1px solid #ddd; } tr:hover { background: #f0f8ff; } .metric { display: inline-block; min-width: 150px; margin: 10px 20px; } .metric-value { font-size: 28px; font-weight: bold; color: #0078d4; } .metric-label { font-size: 12px; color: #666; } .bar { height: 20px; background: #e0e0e0; border-radius: 4px; overflow: hidden; } .bar-fill { height: 100%; border-radius: 4px; } .warning { background: #ff9800; } .good { background: #4caf50; } .danger { background: #f44336; } .timestamp { color: #999; font-size: 12px; } </style> </head> <body> <h1>服务器健康报告</h1> <p class="timestamp">生成时间:$ (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | 计算机:$ ($os .CSName)</p> <div class="card"> <h2>系统概览</h2> <div class="metric"> <div class="metric-value">$usedRamPct %</div> <div class="metric-label">内存使用率</div> </div> <div class="metric"> <div class="metric-value">$ ($cpu .LoadPercentage)%</div> <div class="metric-label">CPU 使用率</div> </div> <div class="metric"> <div class="metric-value">$freeRam GB</div> <div class="metric-label">可用内存</div> </div> <div class="metric"> <div class="metric-value">$totalRam GB</div> <div class="metric-label">总内存</div> </div> </div> <div class="card"> <h2>磁盘状态</h2> <table> <tr><th>驱动器</th><th>文件系统</th><th>总容量</th><th>已使用</th><th>可用</th><th>使用率</th></tr> "@ foreach ($disk in $disks ) { $totalGB = [math ]::Round($disk .Size / 1 GB, 2 ) $freeGB = [math ]::Round($disk .FreeSpace / 1 GB, 2 ) $usedGB = [math ]::Round(($disk .Size - $disk .FreeSpace) / 1 GB, 2 ) $usedPct = [math ]::Round(($disk .Size - $disk .FreeSpace) / $disk .Size * 100 , 1 ) $barClass = if ($usedPct -gt 90 ) { "danger" } elseif ($usedPct -gt 70 ) { "warning" } else { "good" } $html += @" <tr> <td>$ ($disk .DeviceID)</td> <td>$ ($disk .FileSystem)</td> <td>$ {totalGB} GB</td> <td>$ {usedGB} GB</td> <td>$ {freeGB} GB</td> <td> <div class="bar"><div class="bar-fill $barClass " style="width:$usedPct %"></div></div> $usedPct % </td> </tr> "@ } $html += @" </table> </div> <div class="card"> <h2>内存占用 Top 10 进程</h2> <table> <tr><th>进程名</th><th>PID</th><th>内存 (MB)</th></tr> "@ foreach ($proc in $topProcesses ) { $html += " <tr><td>$ ($proc .Name)</td><td>$ ($proc .Id)</td><td>$ ($proc .内存MB)</td></tr>`n" } $html += @" </table> </div> </body> </html> "@ $html | Out-File -FilePath $OutputPath -Encoding UTF8 Write-Host "HTML 报告已生成:$OutputPath " -ForegroundColor Green } New-ServerHealthReport
执行结果示例:
1 HTML 报告已生成:C:\Reports\ServerHealth.html
注意 :HTML 报告可以直接在浏览器中打开,也可以通过邮件发送。结合 Windows 计划任务,可以每日自动生成并发送。
导出 CSV 供外部工具使用 如果需要更复杂的可视化,可以将数据导出为 CSV 格式,供 Excel、Power BI 或 Grafana 使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $report = foreach ($day in 1 ..30 ) { $date = (Get-Date ).AddDays(-$day ) [PSCustomObject ]@ { 日期 = $date .ToString('yyyy-MM-dd' ) CPU平均 = [math ]::Round((Get-Random -Min 20 -Max 80 ) + (Get-Random -Min 0 -Max 100 ) / 100 , 2 ) 内存使用率 = [math ]::Round((Get-Random -Min 40 -Max 85 ) + (Get-Random -Min 0 -Max 100 ) / 100 , 2 ) 磁盘写入MB = [math ]::Round((Get-Random -Min 100 -Max 5000 ) + (Get-Random -Min 0 -Max 100 ) / 100 , 2 ) 网络流量MB = [math ]::Round((Get-Random -Min 500 -Max 20000 ) + (Get-Random -Min 0 -Max 100 ) / 100 , 2 ) } } $report | Export-Csv -Path "C:\Reports\daily_metrics.csv" -NoTypeInformation -Encoding UTF8Write-Host "已导出 $ ($report .Count) 天的指标数据" -ForegroundColor Green$report | ConvertTo-MarkdownTable | Set-Content "C:\Reports\daily_metrics.md"
执行结果示例:
使用 Mermaid 在 Markdown 中嵌入图表 对于 Markdown 格式的报告,可以使用 Mermaid 语法嵌入流程图和甘特图,GitHub 和 GitLab 原生支持渲染:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $mermaid = @" # 运维任务计划 ```mermaid gantt title 2025年5月运维任务 dateFormat YYYY-MM-DD section 基础设施 服务器巡检 :done, des1, 2025-05-01, 2025-05-05 补丁更新 :active, des2, 2025-05-05, 2025-05-10 容量评估 : des3, 2025-05-15, 2025-05-20 section 安全 漏洞扫描 :done, sec1, 2025-05-01, 2025-05-03 安全加固 : sec2, 2025-05-10, 2025-05-15 渗透测试 : sec3, 2025-05-20, 2025-05-25
“@
Set-Content -Path “C:\Reports\tasks_may.md” -Value $mermaid -Encoding UTF8 Write-Host “Mermaid 甘特图 Markdown 已生成” -ForegroundColor Green
Mermaid 甘特图 Markdown 已生成
## 注意事项
1. **Chart 控件依赖**:.NET Chart 控件需要 Windows 桌面环境,在 Server Core 或 Linux 上不可用。跨平台场景建议使用 HTML/CSV 导出方式
2. **图片分辨率**:生产环境中建议将图表尺寸设为 1200x600 以上,确保在高分辨率显示器上清晰
3. **中文字体**:Chart 控件中显示中文需要指定支持中文的字体(如"Microsoft YaHei"),否则可能显示方块
4. **HTML 报告编码**:生成 HTML 文件时务必使用 UTF-8 编码,并在 `<head>` 中声明 `<meta charset="UTF-8">`
5. **自动化调度**:结合 Windows 计划任务或 PowerShell 隐式远程,可以实现每日自动采集数据并生成报告
6. **大数据量**:当数据点超过数千时,.NET Chart 控件的性能会下降,建议对时间序列数据进行采样聚合后再绘图