Picking up from Part 1 and Part 2 in the series, it’s now time to take our collected data and calculated linear trend line and plot them graphically.
Before going any further, download and install the Microsoft Chart Controls on the computer you’re going to run this script from.
There is a lot going on here. Remembering that this is to be inserted into the previous script (in the middle of a loop through each computers hard disks). The summary of the script is:
- Get the capacity of the current drive
- Get the data from the saved .txt file for the last X days for the current drive
- Limit the chart y-axis to a range of numbers specific to the data (you don’t want graphs starting from 0GB when the data is in the terabytes)
- Based on the above range, set appropriate interval/tick values
- Calculate the number of days the disk has left if the trend continues and only create a graph if within X days of exhausting available space
- Create the chart object and chart area
- Plot a horizontal line for the capacity of the disk
- Plot a line for the historical usage of the disk
- Plot the linear trend line, and extend it to show where it hits the disk capacity
- Save the chart to an image file in c:\scripts\diskgraphs
Here’s the script:
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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# Chart size and colours $chartheight = 400; $chartwidth = 800; $usedcolor = "#62B5CC"; $trendcolor = "#FF6699"; $capacitycolor = "#66FF66"; # Set y-axis starting number in GB $minimum = 0; if ($c -gt 30) { $minimum = [system.math]::round(($c * 0.9)/10)*10; } elseif ($c -gt 100) { $minimum = [system.math]::round(($c * 0.95)/50)*50; } elseif ($c -gt 1000) { $minimum = [system.math]::round(($c * 0.95)/100)*100; } # Set y-axis ending number in GB $maximum = [system.math]::round(($capacityGB * 1.05)/10)*10; # Set y-axis tick intervals in GB if ($capacityGB -lt 100) { $yinterval = 5; } elseif ($capacityGB -lt 600) { $yinterval = 20; } elseif ($capacityGB -lt 1000) { $yinterval = 50; } elseif ($capacityGB -lt 2000) { $yinterval = 100; } else { $yinterval = 250; } # Only create graph if trend is positive if ($slope -gt 0) { # Calculate number of days until disk is exhausted $daysleft = [int]((($capacityGB - $c) / $slope) - $samplecount); # Only create graph if disk will be exahuasted in the next 100 days if ($daysleft -lt 100) { # Load chart assemblies [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization") # Create chart object $chart1 = new-object System.Windows.Forms.DataVisualization.Charting.Chart; $chart1.width = $chartwidth; $chart1.height = $chartheight; $chart1.backcolor = [System.Drawing.Color]::White; # Set chart title $roundslope = [system.math]::round($slope,1); $charttitle = $hostname + " - " + $drive.deviceid[0] + ":\" + " Growth Rate: " + $roundslope + "GB/day Exhausted in: " + $daysleft + " days"; [void]$chart1.Titles.Add($charttitle) $chart1.titles[0].Font = "Arial,13pt" $chart1.titles[0].Alignment = "topLeft" # Create chart area $chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea $chartarea.name = "ChartArea1" $chartarea.axisy.title = "Disk Space (GB)" $chartarea.axisx.title = "Date" $chartarea.axisy.Interval = $yinterval $chartarea.axisx.Interval = 1 $chartarea.axisy.minimum = $minimum; $chartarea.axisy.maximum = $maximum; # Add chart area to chart object $chart1.ChartAreas.Add($chartarea) # Create chart legend $legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend $legend.name = "Legend1" # Add chart legend to chart object $chart1.legends.add($legend) # Create Capacity data series on chart [void]$chart1.Series.Add("Capacity") $chart1.series["Capacity"].charttype = "line" $chart1.series["Capacity"].isvisibleinlegend = $true $chart1.series["Capacity"].borderWidth = 3 $chart1.series["Capacity"].chartarea = "ChartArea1" $chart1.series["Capacity"].legend = "Legend1" $chart1.series["Capacity"].color = $capacitycolor; # Plot horizontal line for Capacity onto chart series $datasource | foreach-object {$chart1.Series["Capacity"].points.addxy( $_.date , $capacityGB); } # Create Used data series on chart [void]$chart1.Series.Add("Used") $chart1.series["Used"].charttype = "line" $chart1.series["Used"].borderwidth = 3 $chart1.series["Used"].isvisibleinlegend = $true $chart1.series["Used"].chartarea = "ChartArea1" $chart1.series["Used"].legend = "Legend1" $chart1.series["Used"].color = $usedcolor; # Plot Used data points onto chart series $datasource | foreach-object {$chart1.series["Used"].points.addxy( $_.date , $_.GB); } # Create Trend data series on chart [void]$chart1.Series.Add("Trend") $chart1.series["Trend"].charttype = "line" $chart1.series["Trend"].isvisibleinlegend = $true $chart1.series["Trend"].borderwidth = 3 $chart1.series["Trend"].chartarea = "ChartArea1" $chart1.series["Trend"].legend = "Legend1" $chart1.series["Trend"].color = $trendcolor; $currentpoint = 0; # Plot linear Trend data points onto chart series using previously calculated trend formula $datasource | foreach-object {$ypoint = ($slope * $currentpoint) + $c; $chart1.Series["Trend"].points.addxy( $_.date , $ypoint); $currentpoint++; } $dateadder = 1; # Extend graph x-axis and trend line by plotting Trend data series until capacity is reached while ($daysleft -gt 0) { $ypoint = ($slope * $currentpoint) + $c; $todaydate = get-date -Format "dd/MM/yyyy"; $plotdate = [datetime]::ParseExact(($todaydate),"dd/MM/yyyy", $null).adddays($dateadder); $plotdate = $plotdate.ToShortDateString(); $chart1.series["Trend"].points.addxy($plotdate, $ypoint); $dateadder++; $daysleft--; $currentpoint++; } # Save chart to png file $savefile = "c:\scripts\diskgraphs\" + $hostname + "_" + $drive.deviceid[0] + "_" + (get-date -f yyMMdd) + ".png"; $chart1.SaveImage($savefile,"png"); } } |
After all of that, you should have .png files in c:\scripts\diskgraphs that are in the format of <computername>_<driveletter>_<todays_date>.png
And when you open each image, you should see something like this:
You can now embed these images in HTML or an email to be delivered periodically.
FAQ
Q: Why don’t I get graphs for all my drives?
A: The script is designed to only produce graphs when disk usage is trending upwards AND if that trend suggests the disk will run out of space in less than 100 days. You can change these settings easily to produce graphs for all drives regardless of the slope or predicted days remaining.
Q: What if I wanted a pie/bar/whatever style of chart?
A: Check out the link in the References for more information about other chart types and more theory on how the chart controls really work.
References
https://www.microsoft.com/en-us/download/details.aspx?id=14422
this works good if your data goes up linearly–But what is the solution when the recordings are sinusoidal in nature, e.g. large creation of files over a week and then deletion on the weekend. For something like this, an identifier to determine a sinusoidal growth is necessary and then multi regression is required. or alternatively perform a linear regression on the peaks of your disk space use for each period.
You’re right – the script does not cater for sinusoidal peaks and troughs. The script was primarily designed for “growth over time” scenarios which (at the time of writing) was found to be a major ongoing headache.
I don’t think it would be too difficult to modify the script to look for various patterns of change. IE: tracking large shifts (in % or GB) form the previous day/week, even though the trend suggests no growth.