six demon bag

Wind, fire, all that kind of thing!

2014-02-26

A Bar Graph for the PowerShell Console

As a sysadmin I frequently have the need to get an overview of the utilization of particular system resources (disk space or memory for instance). Visualizing the numbers greatly helps with spotting bottlenecks.

One way to visualize data with PowerShell are DataVisualization objects in Windows Forms, which are rather versatile, but not exactly what I would consider straightforward. They also might be overkill for various tasks. The current usage of a system resource for instance could easily be displayed with a bar graph in a text console.


Jeffrey Hicks wrote a nifty PowerShell function which does just that. However, there are some details about it that I'd rather have differently:

  • Print just the bar for a single value instead of the entire graph. That would also allow me to build captions from more than just one property without having to resort to calculated properties.
  • Use a fixed default width that can be overridden by the caller instead of always using the entire width of the console window.
  • Optionally display the percent value on the bar (the box graphic characters used by the original function prevent that).
  • Optionally display additional information on the right side of the graph.

So this is what I came up with:

function Out-Gauge {
  [CmdletBinding()]
  Param(
    [parameter(Mandatory=$true)][string]$Caption,
    [parameter(Mandatory=$true)][double]$Value,
    [string]$Info = '',
    [int]$CaptionWidth = 20,
    [int]$GaugeWidth = 60,
    [int]$WarningLimit = 70,
    [int]$CriticalLimit = 90,
    [ConsoleColor[]]$OKColors = @([ConsoleColor]::Green, [ConsoleColor]::Black),
    [ConsoleColor[]]$WarningColors = @([ConsoleColor]::Yellow, [ConsoleColor]::Black),
    [ConsoleColor[]]$CriticalColors = @([ConsoleColor]::Red, [ConsoleColor]::White),
    [switch][bool]$ShowValue = $false
  )

  # set foreground and background color for the bar
  if ($Value -lt $WarningLimit) {
    $bgColor = $OKColors[0]
    $fgColor = $OKColors[1]
  } elseif ($Value -lt $CriticalLimit) {
    $bgColor = $WarningColors[0]
    $fgColor = $WarningColors[1]
  } else {
    $bgColor = $CriticalColors[0]
    $fgColor = $CriticalColors[1]
  }

  # calculate bar width
  if ( $ShowValue ) {
    $gauge = " {0,-$($GaugeWidth - 1):p}" -f ($Value / 100)
  } else {
    $gauge = ' ' * $GaugeWidth
  }
  $filled = [int]($Value / 100 * $GaugeWidth)

  # print caption
  Write-Host ("{0,-$CaptionWidth} {1}" -f $Caption, ([string][char]9474)) -NoNewline
  # print bar
  Write-Host $gauge.SubString(0, $filled) -Foreground $fgColor -Background $bgColor -NoNewline
  Write-Host $gauge.SubString($filled) -NoNewline
  # print info text
  Write-Host ("{0} {1}" -f ([string][char]9474), $Info)
}

With this I can build a function for showing the used disk space of cluster shared volumes like this:

function Show-CsvUsage {
  [CmdletBinding()]
  Param(
    [parameter(Mandatory=$true)][string]$Cluster
  )

  Get-ClusterSharedVolume -Cluster $Cluster | sort Name | % {
    $caption = "{0,-7} ({1})" -f (Split-Path -Leaf $_.SharedVolumeInfo.FriendlyVolumeName), $_.Name
    $value   = 100.0 -$_.SharedVolumeInfo.Partition.PercentFree
    $size    = "{0:n2} TB" -f ($_.SharedVolumeInfo.Partition.Size / 1TB)

    Out-Gauge -Caption $caption -Value $value -Info $size -ShowValue
  }
}

Cluster Shared Volume Overview

Posted 23:38 [permalink]