4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[備忘録] PowerShellでSVGを描いてみた|管理スクリプトに視覚を!

Last updated at Posted at 2025-07-05

はじめに

image.png

PowerShellといえばシステム管理やバッチ処理のイメージが強いですが、実はSVG(Scalable Vector Graphics)を生成することも可能です。テキストベースの出力だけでなく、視覚的なグラフィックを生成できれば、運用レポートやダッシュボードがより分かりやすくなります。

この記事では、PowerShellを使ってSVGを描画する基本的な方法から、実際の運用で使える実例まで紹介します。

動作確認した環境

Windows 11
PowerShell 5.1

なぜPowerShellでSVG?

PowerShellだけでグラフィックを生成できるため、追加ツールは不要です。SVGはベクター形式のためファイルサイズが小さく、解像度に依存しない美しい表示が可能です。また、主要なブラウザに対応しているため、HTMLレポートなどにも手軽に埋め込めます。

基本的なSVG描画

まずは簡単な図形から始めてみましょう。

円を描く

function New-SVGCircle {
    param(
        [int]$Width = 200,
        [int]$Height = 200,
        [int]$CenterX = 100,
        [int]$CenterY = 100,
        [int]$Radius = 50,
        [string]$Fill = "blue"
    )
    
    $svg = @"
<svg width="$Width" height="$Height" xmlns="http://www.w3.org/2000/svg">
    <circle cx="$CenterX" cy="$CenterY" r="$Radius" fill="$Fill" stroke="black" stroke-width="2"/>
</svg>
"@
    
    return $svg
}

# 使用例
$circle = New-SVGCircle -Fill "red"
$circle | Out-File "circle.svg" -Encoding UTF8

image.png

四角形を描く


function New-SVGRectangle {
    param(
        [int]$Width = 200,
        [int]$Height = 200,
        [int]$X = 50,
        [int]$Y = 50,
        [int]$RectWidth = 100,
        [int]$RectHeight = 80,
        [string]$Fill = "green"
    )
    
    $svg = @"
<svg width="$Width" height="$Height" xmlns="http://www.w3.org/2000/svg">
    <rect x="$X" y="$Y" width="$RectWidth" height="$RectHeight" 
          fill="$Fill" stroke="black" stroke-width="2"/>
</svg>
"@
    
    return $svg
}

# 使用例
$rectangle = New-SVGRectangle -Fill "lightblue" -RectWidth 120 -RectHeight 60
$rectangle | Out-File "rectangle.svg" -Encoding UTF8

image.png

実用例 プロセス監視ダッシュボード

function New-ProcessMonitorSVG {
    param(
        [array]$ProcessData
    )
    
    $width = 600
    $height = 400
    $maxProcesses = 10
    
    # 上位10プロセスを取得
    $topProcesses = $ProcessData | Sort-Object CPU -Descending | Select-Object -First $maxProcesses
    $maxCpu = ($topProcesses | Measure-Object CPU -Maximum).Maximum
    
    $svg = @"
<svg width="$width" height="$height" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <linearGradient id="cpuGradient" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" style="stop-color:#4CAF50;stop-opacity:1" />
            <stop offset="50%" style="stop-color:#FFC107;stop-opacity:1" />
            <stop offset="100%" style="stop-color:#F44336;stop-opacity:1" />
        </linearGradient>
    </defs>
    
    <!-- タイトル -->
    <text x="300" y="25" text-anchor="middle" font-family="Arial" font-size="18" font-weight="bold">
        プロセス CPU使用率 TOP10
    </text>
    
    <!-- ヘッダー -->
    <rect x="20" y="40" width="560" height="25" fill="#e0e0e0" stroke="#999"/>
    <text x="30" y="57" font-family="Arial" font-size="12" font-weight="bold">プロセス名</text>
    <text x="250" y="57" font-family="Arial" font-size="12" font-weight="bold">CPU使用率</text>
    <text x="450" y="57" font-family="Arial" font-size="12" font-weight="bold">メモリ(MB)</text>
"@
    
    $y = 65
    foreach ($process in $topProcesses) {
        $barWidth = if ($maxCpu -gt 0) { ($process.CPU / $maxCpu) * 150 } else { 0 }
        $memoryMB = [math]::Round($process.WorkingSet / 1MB, 1)
        
        $svg += @"
    
    <!-- プロセス行 -->
    <rect x="20" y="$y" width="560" height="25" fill="white" stroke="#ddd"/>
    <text x="30" y="$(($y + 17))" font-family="Arial" font-size="11">$($process.ProcessName)</text>
    
    <!-- CPU使用率バー -->
    <rect x="250" y="$(($y + 5))" width="$barWidth" height="15" fill="url(#cpuGradient)"/>
    <text x="$(250 + $barWidth + 5)" y="$(($y + 17))" font-family="Arial" font-size="10">$([math]::Round($process.CPU, 1))%</text>
    
    <!-- メモリ使用量 -->
    <text x="450" y="$(($y + 17))" font-family="Arial" font-size="11">$memoryMB</text>
"@
        $y += 25
    }
    
    $svg += @"
    
    <!-- 更新時刻 -->
    <text x="500" y="390" font-family="Arial" font-size="10" fill="#666">
        更新: $(Get-Date -Format "yyyy/MM/dd HH:mm:ss")
    </text>
</svg>
"@
    
    return $svg
}

# プロセス情報を取得
$processes = Get-Process | Where-Object {$_.CPU -gt 0} | Select-Object ProcessName, CPU, WorkingSet

# SVGを生成
$processSvg = New-ProcessMonitorSVG -ProcessData $processes
$processSvg | Out-File "process_monitor.svg" -Encoding UTF8

image.png

注意事項:
Get-ProcessコマンドレットのCPUプロパティは、現在のCPU使用率(%)ではなく、プロセス開始からの累積CPU時間(秒)を返します。そのため、表示される数値は実際の使用率とは異なります。リアルタイムのCPU使用率を取得したい場合は、WMIやPerformance Counterを使用する必要があります。

実用例 ネットワーク接続状況の可視化

function New-NetworkConnectionChart {
    $connections = Get-NetTCPConnection | Group-Object State | Sort-Object Count -Descending
    
    $width = 500
    $height = 300
    $centerX = 250
    $centerY = 150
    $radius = 80
    
    $total = ($connections | Measure-Object Count -Sum).Sum
    $currentAngle = 0
    
    $svg = @"
<svg width="$width" height="$height" xmlns="http://www.w3.org/2000/svg">
    <!-- タイトル -->
    <text x="$centerX" y="25" text-anchor="middle" font-family="Arial" font-size="16" font-weight="bold">
        ネットワーク接続状況
    </text>
"@
    
    $colors = @("#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7", "#DDA0DD")
    $colorIndex = 0
    
    foreach ($connection in $connections) {
        $percentage = ($connection.Count / $total) * 100
        $angle = ($connection.Count / $total) * 360
        
        $startAngle = [math]::PI * $currentAngle / 180
        $endAngle = [math]::PI * ($currentAngle + $angle) / 180
        
        $x1 = $centerX + $radius * [math]::Cos($startAngle)
        $y1 = $centerY + $radius * [math]::Sin($startAngle)
        $x2 = $centerX + $radius * [math]::Cos($endAngle)
        $y2 = $centerY + $radius * [math]::Sin($endAngle)
        
        $largeArc = if ($angle -gt 180) { 1 } else { 0 }
        
        $svg += @"
    
    <!-- $($connection.Name) セクション -->
    <path d="M $centerX $centerY L $x1 $y1 A $radius $radius 0 $largeArc 1 $x2 $y2 Z" 
          fill="$($colors[$colorIndex])" stroke="white" stroke-width="2"/>
"@
        
        $currentAngle += $angle
        $colorIndex = ($colorIndex + 1) % $colors.Length
    }
    
    # 凡例
    $legendY = 50
    $colorIndex = 0
    foreach ($connection in $connections) {
        $percentage = [math]::Round(($connection.Count / $total) * 100, 1)
        
        $svg += @"
    
    <!-- 凡例項目 -->
    <rect x="350" y="$legendY" width="15" height="15" fill="$($colors[$colorIndex])"/>
    <text x="370" y="$(($legendY + 12))" font-family="Arial" font-size="12">
        $($connection.Name): $($connection.Count) ($percentage%)
    </text>
"@
        
        $legendY += 20
        $colorIndex = ($colorIndex + 1) % $colors.Length
    }
    
    $svg += @"
</svg>
"@
    
    return $svg
}

$networkChart = New-NetworkConnectionChart
$networkChart | Out-File "network_connections.svg" -Encoding UTF8

image.png

HTMLレポートに組み込む

生成したSVGをHTMLレポートに組み込んで、包括的なシステム監視ダッシュボードを作成できます。

function New-SystemDashboard {
    # 各種SVGを生成
    $resourceChart = New-ResourceUsageChart -CpuUsage 45 -MemoryUsage 67 -DiskUsage 82
    $processChart = New-ProcessMonitorSVG -ProcessData (Get-Process | Where-Object {$_.CPU -gt 0} | Select-Object ProcessName, CPU, WorkingSet)
    $networkChart = New-NetworkConnectionChart
    
    $html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>システム監視ダッシュボード</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
        .dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
        .panel { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .full-width { grid-column: span 2; }
        h1 { text-align: center; color: #333; }
        .timestamp { text-align: center; color: #666; margin-bottom: 30px; }
    </style>
</head>
<body>
    <h1>システム監視ダッシュボード</h1>
    <div class="timestamp">更新日時: $(Get-Date -Format "yyyy年MM月dd日 HH:mm:ss")</div>
    
    <div class="dashboard">
        <div class="panel">
            $resourceChart
        </div>
        
        <div class="panel">
            $networkChart
        </div>
        
        <div class="panel full-width">
            $processChart
        </div>
    </div>
</body>
</html>
"@
    
    return $html
}

$dashboard = New-SystemDashboard
$dashboard | Out-File "system_dashboard.html" -Encoding UTF8

まとめ

PowerShellでSVGを生成すれば、従来のテキスト中心の出力を視覚的でわかりやすい形に変えることができます。特にシステム管理の現場では、たとえば定期レポートの自動化、アラートの視覚化、パフォーマンス分析のグラフ化など、さまざまな用途に活用できます。PowerShellの柔軟なスクリプト処理と、SVGの軽量かつ高い視認性を組み合わせることで、専用ツールを使わずに効果的な可視化を実現できます。日々の運用業務への導入をぜひ検討してみてください。

参考リンク

参考情報

記事を書いたあとに気づいたんですが、次回チャンスがあれば試してみたいです。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?