PowerShell functions for working with Microsoft Chart Controls.
# <script>
#
# <description>
#
# - Defines functions for working with Microsoft Chart Control for .NET 3.5 Framework
# - Pipe output of Powershell command to Out-Chart function and specify chart type
# - Chart will display in form or save to image file
# - Real-time charts are supported by passing in a script block
#
# Requires NET Framework 3.5 and Microsoft Chart Controls for Microsoft .NET Framework 3.5
#
# My thanks to Richard MacDonald for his wonderful post on Charting with PowerShell
# http://blogs.technet.com/richard_macdonald/archive/2009/04/28/3231887.aspx
#
# http://poshcode.org/1205
#
# </description>
#
# <usage>
#
# ./LibraryChart.ps1
#
# -------------------------- EXAMPLE 1 --------------------------
#
# This command will produce a default column chart:
# Get-Process | Sort-Object -Property WS | Select-Object Name,WS -Last 5 | out-chart -xField 'name' -yField 'WS'
#
# -------------------------- EXAMPLE 2 --------------------------
#
# This command will output the chart to a file:
# Get-Process | Sort-Object -Property WS | Select-Object Name,WS -Last 5 | out-chart -xField 'name' -yField 'WS' -filename 'c:\process.png'
#
# -------------------------- EXAMPLE 3 --------------------------
#
# This command will produce a pie chart:
# Get-Process | Sort-Object -Property WS | Select-Object Name,WS -Last 5 | out-chart -xField 'name' -yField 'WS' -chartType 'Pie'
#
# -------------------------- EXAMPLE 4 --------------------------
#
# This command will produce a real-time line chart:
# out-chart -xField 'name' -yField 'WS' -scriptBlock {Get-Process | Sort-Object -Property WS | Select-Object Name,WS -Last 1} -chartType 'line'
#
# </usage>
#
# <author>
#
# Chad Miller
#
# </author>
# </script>
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")
#######################
function New-Chart
{
param ([int]$width,[int]$height,[int]$left,[int]$top,$chartTitle)
# create chart object
$global:Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$global:Chart.Width = $width
$global:Chart.Height = $height
$global:Chart.Left = $left
$global:Chart.Top = $top
# create a chartarea to draw on and add to chart
$chartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$global:chart.ChartAreas.Add($chartArea)
[void]$global:Chart.Titles.Add($chartTitle)
# change chart area colour
$global:Chart.BackColor = [System.Drawing.Color]::Transparent
} #New-Chart
#######################
function New-BarColumnChart
{
param ([hashtable]$ht, $chartType='Column', $chartTitle,$xTitle,$yTitle, [int]$width,[int]$height,[int]$left,[int]$top,[bool]$asc)
New-Chart -width $width -height $height -left $left -top $top -chartTile $chartTitle
$chart.ChartAreas[0].AxisX.Title = $xTitle
$chart.ChartAreas[0].AxisY.Title = $yTitle
[void]$global:Chart.Series.Add("Data")
$global:Chart.Series["Data"].Points.DataBindXY($ht.Keys, $ht.Values)
$global:Chart.Series["Data"].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::$chartType
if ($asc)
{
$global:Chart.Series["Data"].Sort([System.Windows.Forms.DataVisualization.Charting.PointSortOrder]::Ascending, "Y")
}
else
{
$global:Chart.Series["Data"].Sort([System.Windows.Forms.DataVisualization.Charting.PointSortOrder]::Descending, "Y")
}
$global:Chart.Series["Data"]["DrawingStyle"] = "Cylinder"
$global:chart.Series["Data"].IsValueShownAsLabel = $true
$global:chart.Series["Data"]["LabelStyle"] = "Top"
} #New-BarColumnChart
#######################
function New-LineChart
{
param ([hashtable]$ht,$chartTitle, [int]$width,[int]$height,[int]$left,[int]$top)
New-Chart -width $width -height $height -left $left -top $top -chartTile $chartTitle
[void]$global:Chart.Series.Add("Data")
#$global:Chart.Series["Data"].Points.AddXY($(get-date), $($ht.Values))
$global:Chart.Series["Data"].Points.DataBindXY($ht.Keys,$ht.Values)
#$global:Chart.Series["Data"].XValueType = [System.Windows.Forms.DataVisualization.Charting.ChartValueType]::Time
#$global:Chart.chartAreas[0].AxisX.LabelStyle.Format = "hh:mm:ss"
#$global:Chart.chartAreas[0].AxisX.LabelStyle.Interval = 1
#$global:Chart.chartAreas[0].AxisX.LabelStyle.IntervalType = [System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType]::Seconds
$global:Chart.Series["Data"].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Line
#$global:chart.Series["Data"].IsValueShownAsLabel = $false
} #New-LineChart
#######################
function New-PieChart
{
param ([hashtable]$ht,$chartTitle, [int]$width,[int]$height,[int]$left,[int]$top)
New-Chart -width $width -height $height -left $left -top $top -chartTile $chartTitle
[void]$global:Chart.Series.Add("Data")
$global:Chart.Series["Data"].Points.DataBindXY($ht.Keys, $ht.Values)
$global:Chart.Series["Data"].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Pie
$global:Chart.Series["Data"]["PieLabelStyle"] = "Outside"
$global:Chart.Series["Data"]["PieLineColor"] = "Black"
#$global:chart.Series["Data"].IsValueShownAsLabel = $true
#$global:chart.series["Data"].Label = "#PERCENT{P1}"
#$legend = New-object System.Windows.Forms.DataVisualization.Charting.Legend
#$global:Chart.Legends.Add($legend)
#$Legend.Name = "Default"
} #New-PieChart
#######################
function Remove-Points
{
param($name='Data',[int]$maxPoints=200)
while ($global:chart.Series["$name"].Points.Count > $maxPoints)
{
$global:chart.Series["$name"].Points.RemoveAT(0)
}
} #Remove-Points
#######################
function Out-Form
{
param($interval,$scriptBlock,$xField,$yField)
# display the chart on a form
$global:Chart.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right -bor
[System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left
$Form = New-Object Windows.Forms.Form
$Form.Text = 'PowerCharts'
$Form.Width = 600
$Form.Height = 600
$Form.controls.add($global:Chart)
if ($scriptBlock -is [ScriptBlock])
{
if (!($xField -or $yField))
{
throw 'xField and yField required with scriptBlock parameter.'
}
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = $interval
$timer.add_Tick(
{
$ht = &$scriptBlock | ConvertTo-HashTable $xField $yField
if ($global:Chart.Series["Data"].ChartTypeName -eq 'Line')
{
Remove-Points
$ht | foreach { $global:Chart.Series["Data"].Points.AddXY($($_.Keys), $($_.Values)) }
}
else
{
$global:Chart.Series["Data"].Points.DataBindXY($ht.Keys, $ht.Values)
}
$global:chart.ResetAutoValues()
$global:chart.Invalidate()
})
$timer.Enabled = $true
$timer.Start()
}
$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog()
} #Out-Form
#######################
function Out-ImageFile
{
param($fileName,$fileformat)
$global:Chart.SaveImage($fileName, $fileformat)
}
#######################
### ConvertTo-Hashtable function based on code by Jeffery Snover
### http://blogs.msdn.com/powershell/archive/2008/11/23/poshboard-and-convertto-hashtable.aspx
#######################
function ConvertTo-Hashtable
{
param([string]$key, $value)
Begin
{
$hash = @{}
}
Process
{
$thisKey = $_.$Key
$hash.$thisKey = $_.$Value
}
End
{
Write-Output $hash
}
} #ConvertTo-Hashtable
#######################
function Out-Chart
{
param( $xField=$(throw 'Out-Chart:xField is required'),
$yField=$(throw 'Out-Chart:yField is required'),
$chartType='Column',
$chartTitle,
[int]$width=500,
[int]$height=400,
[int]$left=40,
[int]$top=30,
$filename,
$fileformat='png',
[int]$interval=1000,
$scriptBlock,
[switch]$asc
)
Begin
{
$ht = @{}
}
Process
{
if ($_)
{
$thisKey = $_.$xField
$ht.$thisKey = $_.$yField
}
}
End
{
if ($scriptBlock)
{
$ht = &$scriptBlock | ConvertTo-HashTable $xField $yField
}
switch ($chartType)
{
'Bar' {New-BarColumnChart -ht $ht -chartType $chartType -chartTitle $chartTitle -width $width -height $height -left $left -top $top -asc $($asc.IsPresent)}
'Column' {New-BarColumnChart -ht $ht -chartType $chartType -chartTitle $chartTitle -width $width -height $height -left $left -top $top -asc $($asc.IsPresent)}
'Pie' {New-PieChart -chartType -ht $ht -chartTitle $chartTitle -width $width -height $height -left $left -top $top }
'Line' {New-LineChart -chartType -ht $ht -chartTitle $chartTitle -width $width -height $height -left $left -top $top }
}
if ($filename)
{
Out-ImageFile $filename $fileformat
}
elseif ($scriptBlock )
{
Out-Form $interval $scriptBlock $xField $yField
}
else
{
Out-Form
}
}
} #Out-Chart