Building a Windows Storage Dashboard, Part 3: Incorporating Historical DataBuilding a Windows Storage Dashboard, Part 3: Incorporating Historical DataBuilding a Windows Storage Dashboard, Part 3: Incorporating Historical Data
The final part of this three-part series on building a Windows storage dashboard details how to incorporate the historical data collected in Part 2 into the dashboard created in Part 1.
[Editor's Note: This is Part 3 of a three-part series on building a Windows storage dashboard.]
In the previous article in this series , I showed you how to create a PowerShell script to collect storage metrics and save that data to a CSV file. By scheduling this script to run at periodic intervals, you can compile historical data reflecting your disk consumption over time. So with that in mind, I want to modify the script that I created in Part 1 of this series so that it now reflects historical data for the selected disk.
Once again, I am not going to do a line-by-line walkthrough of the script because of the script's length. However, I will call attention to some of the more important bits of code, and then I will provide you with the full script at the end of this article. You can see my new and improved script in Figure 1.
adding historical data to a Windows storage dashboard
Figure 1:I have added historical data to my dashboard.
The first thing I did when revising my original script was to create a couple of new GUI objects. I created a label called $HistoryLabel and used it to display the words "Selected Disk Consumption Trend" on the screen. The other GUI object that I created was a second chart, which is used to display the actual data. I am calling this chart $Chart2.
One thing that I wanted to point out about the new chart is that the X axis title is Timestamp and the times that appear along the X axis are formatted as MM-dd HH:mm (month – day Hour:minutes). The only reason why I used this particular format is because of the frequency with which I was collecting data. You will likely want to modify the format to better align with your own data sampling frequency.
Related:PowerShell Remoting in a Workgroup Environment: A Step-by-Step Guide
The upper portion of the script is still very similar to what I showed you in Part 1 of this series. The historical data doesn't really begin to come into play until the event handler that controls what happens when a drive letter is selected from the combo box. The one exception to this is that the CSV file is read into a variable called $Data near the top of the script.
The first thing that the event handler does with regard to the historical data is to filter the data. Here are the lines of code that handle the filtering process:
$FilteredData = $Data | Where-Object { $_.Drive -eq $CurrentDiskDeviceID[0] }
$FilteredData = $FilteredData | Sort-Object { [datetime]::Parse($_.Timestamp) }The first of these two lines of code creates a variable called Filtered Data. This variable contains all of the records within the $Data variable (the original data from our CSV file) matching the selected drive letter.
One thing that I want to point out about this line of code is that the comparison checks to see if $_.Drive is equal to $CurrentDiskDeviceID[0]. In this case, $_.Drive is the drive letter that was read from the CSV file, and the $CurrentDiskDeviceID is the drive letter that was selected from the drop-down menu. You will notice, however, that the $CurrentDiskDeviceID reference contains [0] at the end. The reason for this is that the disks listed in the drop-down menu contain a colon after the drive letter, whereas the CSV file contains a drive letter, but without the colon. The [0] strips the colon so that the code can make a comparison between the drive letters.
Related:Simplify PowerShell Output With the Expression Command
The second line of code shown above takes the filtered data and sorts it by the timestamp so that more recent events appear at the bottom of the list, while older events appear at the top of the list.
The last two steps in the process are to add the filtered data to the chart series and to dynamically scale the chart's Y axis. The reason for dynamically scaling the Y axis is that even within a single system, disks can be vastly different in size. As such, a Y-axis scale that does a good job of displaying one disk might not do so well for displaying another disk. I am handling the dynamic scaling by using the maximum and minimum data values (plus and minus some padding) to set the scale of the chart. Here is what the dynamic scaling code looks like:
Related:Why Can’t PowerShell Session Access My Network Volumes?
# Dynamically Set Y-axis Scale
$UsedValues = $FilteredData | ForEach-Object { [double]$_.UsedGB }
$MinY = ($UsedValues | Measure-Object -Minimum).Minimum
$MaxY = ($UsedValues | Measure-Object -Maximum).Maximum
$Padding = 5
$Chart2.ChartAreas["MainArea"].AxisY.Minimum = [math]::Floor($MinY - $Padding)
$Chart2.ChartAreas["MainArea"].AxisY.Maximum = [math]::Ceiling($MaxY + $Padding)The Full Script
So now that I have talked about how the historical data can be added to the dashboard, I want to provide you with the full script in its entirety. Here is the code:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
Add-Type -AssemblyName System.Drawing
# Load Data From CSV File
$CSVPath = "C:\Scripts\DiskUsageHistory.csv"
if (-Not (Test-Path $CSVPath)) {
[System.Windows.Forms.MessageBox]::Show("CSV file not found: $csvPath", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
return
}
$Data = Import-CSV -Path $CSVPath
# Create Form
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Disk Usage Monitor with SMART Info"
$Form.Width = 1920
$Form.Height = 1080
# Chart setup
$Chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Location = New-Object System.Drawing.Point(20, 20)
$Chart.Size = New-Object System.Drawing.Size(1000,400)
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea) | Out-Null
# Series for Used Space
$UsedSeries = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$UsedSeries.Name = "UsedSpace"
$UsedSeries.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::StackedBar
$UsedSeries.Color = [System.Drawing.Color]::LightBlue
$Chart.Series.Add($UsedSeries) | Out-Null
# Series for Free Space
$FreeSeries = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$FreeSeries.Name = "FreeSpace"
$FreeSeries.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::StackedBar
$FreeSeries.Color = [System.Drawing.Color]::LightGreen
$Chart.Series.Add($FreeSeries) | Out-Null
$Form.Controls.Add($Chart) | Out-Null
$SelectDiskLabel = New-Object System.Windows.Forms.Label
$SelectDiskLabel.AutoSize = $True
$SelectDiskLabel.Location = New-Object System.Drawing.Point(1050, 20)
$SelectDiskLabel.Font = New-Object System.Drawing.Font("Arial", 14)
$SelectDiskLabel.Text = "Select a Disk"
$Form.Controls.Add($SelectDiskLabel) | Out-Null
# ComboBox for selecting drives
$ComboBox = New-Object System.Windows.Forms.ComboBox
$ComboBox.Location = New-Object System.Drawing.Point(1050, 50)
$ComboBox.Font = New-Object System.Drawing.Font("Arial", 14)
$ComboBox.Width = 300
$Form.Controls.Add($ComboBox) | Out-Null
# Label for top files
$FilesLabel = New-Object System.Windows.Forms.Label
$FilesLabel.AutoSize = $True
$FilesLabel.Location = New-Object System.Drawing.Point(1050, 100)
$FilesLabel.Font = New-Object System.Drawing.Font("Arial", 14)
$FilesLabel.Text = "Top 5 Largest Files:"
$Form.Controls.Add($FilesLabel) | Out-Null
# Label for Summary Info
$SummaryLabel = New-Object System.Windows.Forms.Label
$SummaryLabel.AutoSize = $True
$SummaryLabel.Location = New-Object System.Drawing.Point(20, 450)
$SummaryLabel.Font = New-Object System.Drawing.Font("Arial", 14)
$Form.Controls.Add($SummaryLabel) | Out-Null
# Label for SMART Info
$SmartLabel = New-Object System.Windows.Forms.Label
$SmartLabel.AutoSize = $True
$SmartLabel.Location = New-Object System.Drawing.Point(20, 500)
$SmartLabel.Font = New-Object System.Drawing.Font("Arial", 14)
$SmartLabel.Text = "SMART Info:"
$Form.Controls.Add($SmartLabel) | Out-Null
# Label for SMART Info
$HistoryLabel = New-Object System.Windows.Forms.Label
$HistoryLabel.AutoSize = $True
$HistoryLabel.Location = New-Object System.Drawing.Point(1050, 600)
$HistoryLabel.Font = New-Object System.Drawing.Font("Arial", 14)
$HistoryLabel.Text = "Selected Disk Consumption Trend:"
$Form.Controls.Add($HistoryLabel) | Out-Null
$TopFilesOutput = New-Object System.Windows.Forms.TextBox
$TopFilesOutput.Multiline = $True
$TopFilesOutput.Location = New-Object System.Drawing.Point(1050, 150)
$TopFilesOutput.Size = New-Object System.Drawing.Size(850,400)
$TopFilesOutput.ReadOnly = $True
$TopFilesOutput.Font = New-Object System.Drawing.Font("Arial", 14)
$TopFilesOutput.ScrollBars = "Vertical"
$Form.Controls.Add($TopFilesOutput) | Out-Null
$SmartInfoOutput = New-Object System.Windows.Forms.TextBox
$SmartInfoOutput.Multiline = $TrueAbout the Author
Technology Analyst
Brien Posey is a bestselling technology author, a speaker, and a 20X Microsoft MVP. In addition to his ongoing work in IT, Posey has spent the last several years training as a commercial astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space.
You May Also Like
Enterprise Connect 2026 – All In on What’s Next