How To Build a Disk Space Pie Chart in PowerShell

This article ends our series about using PowerShell to visualize disk space usage. Part 3 explains how to generate a pie chart that displays your space.

Brien Posey

December 24, 2024

9 Min Read
a hand-drawn hard disk pointing to a pie chart on a blue print background, with a snippet of the powershell code and the word powershell

In this series, I have shown you how my script’s folder tree works and how to generate a list of the largest files on a hard disk. Next, I will explain how the script produces a pie chart.

Part 1: Track Disk Space With a PowerShell Folder Tree

Part 2: Identify the 10 Largest Files on Your Disk

Part 3: Building a Disk Space Pie Chart // Complete Script

The Update-PieChart Function

I designed the script so that when you click a node in the tree, it calls a function called Update-PieChart. The folder path you select by clicking the node is passed to this function.

Here is what the function looks like:


    Function Update-PieChart {
    param (
        [String]$FolderPath
    )

    # Get the size of the selected folder (in bytes)
    $FolderSize = Get-FolderSize -FolderPath $FolderPath

	# Calculate Used, Free, and Total Space on Drive

	$DriveLetter = $SelectedDrive[0]
	$Drive = Get-PSDrive -Name $DriveLetter

        $FreeSpace = $Drive.Free
        $UsedSpace = $Drive.Used
        $TotalSpace = $Drive.Used + $Drive.Free

        # Update the pie chart with disk space and folder size
        $Series.Points.Clear()
      	$Series.Points.AddXY("Used Space", $UsedSpace)
	$Series.Points.AddXY("Free Space", $FreeSpace)  
        $Series.Points.AddXY("Folder Size", $FolderSize)

	$DisplayTotalSpace= $([math]::Round($TotalSpace / 1GB, 2))
	$DisplayUsedSpace= $([math]::Round($UsedSpace / 1GB, 2))
	$DisplayFreeSpace = $([math]::Round($FreeSpace / 1GB, 2))
	$DisplayFolderSpace= $([math]::Round($FolderSize / 1GB, 2))
	
	$TotalSpaceLabel.Text = "Total Disk Space: - $DisplayTotalSpace GB"
	$FreeSpaceLabel.Text = "Free Space - $DisplayFreeSpace GB"
	$UsedSpaceLabel.Text = "Used Space - $DisplayUsedSpace GB"        
        $FolderSpaceLabel.Text = "Selected Folder Space - $DisplayFolderSpace GB"

        # Set the chart colors
        $Series.Points[0].Color = [System.Drawing.Color]::FromArgb(255, 0, 0)  # Red for used space
        $Series.Points[1].Color = [System.Drawing.Color]::FromArgb(0, 255, 0)  # Green for free space
        $Series.Points[2].Color = [System.Drawing.Color]::FromArgb(0, 0, 255)  # Blue for folder size

}

Breakdown of the Update-PieChart Function

Calculating the folder size

The first thing the Update-PieChart function does is call another function, Get-FolderSize. As the name suggests, this function calculates the total size of all files in the selected folder and its subfolders. It does this by recursively executing the Get-ChildItem cmdlet, starting from the selected path. The list of files gets mapped to the $Files variable, and the total folder size is determined using $Files.Length.

Calculating drive space

The function then executes the Get-PSDrive cmdlet on the designated hard disk. The command returns various statistics, such as free space and used space. These values are stored in the $FreeSpace and $UsedSpace variables, respectively. Since the Get-PSDrive cmdlet doesn’t provide the total disk size, I calculate it by adding $FreeSpace and $UsedSpace, storing the result in $TotalSpace.

Related:How To Visualize SQL Server Data in PowerShell (With Sample Script)

Adding data to the pie chart

After populating the $FreeSpace, $UsedSpace, and $TotalSpace variables, I add $FreeSpace and $UsedSpace to the chart as a series. I also add the $FolderSize variable, which reflects the size of the selected folder.

Next, I create four new variables: $DisplayTotalSpace, $DisplayUsedSpace, $DisplayFreeSpace, and $DisplayFolderSpace. These store the total disk space, used space, free space, and space consumed by the selected folder, all converted to gigabytes. I use these variables for the text summary that appears beneath the chart.

Setting the pie chart colors

The last code section sets the chart colors: green for free space, red for used space, and blue for the space consumed by the selected folder.

Complete Script

Now that I have explained how the script’s components work, here is the script in its entirety:


    $SelectedDrive = "W:"

# Load the necessary .NET assemblies for Windows Forms and Charting
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms.DataVisualization

# Create the Form
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Folder Tree and Disk Usage"
$Form.Width = 1400
$Form.Height = 900

# Create the TreeView control
$FolderTree = New-Object System.Windows.Forms.TreeView
$FolderTree.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Regular)
$FolderTree.Location = "20,20"
$FolderTree.Size = "700,500"
$Form.Controls.Add($FolderTree)

# Create the Chart control for the pie chart
$Chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Location = "800,20"
$Chart.Size = "500,500"
$Form.Controls.Add($Chart)

# Set up the chart area
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea)

# Add a series for the pie chart
$Series = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$Series.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Pie
$Chart.Series.Add($Series)

# Create a custom panel to hold the legend
$LegendPanel = New-Object System.Windows.Forms.Panel
$LegendPanel.Width = 400
$LegendPanel.Height = 400
$LegendPanel.Top = 600
$LegendPanel.Left = 1050
$Form.Controls.Add($LegendPanel)

# Add Labels to simulate legend
$TotalSpaceLabel = New-Object System.Windows.Forms.Label
$TotalSpaceLabel.Size = "300,25"
$TotalSpaceLabel.Text = "Used Space"
$TotalSpaceLabel.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Bold)
$TotalSpaceLabel.ForeColor = [System.Drawing.Color]::Black   
$TotalSpaceLabel.Location = New-Object System.Drawing.Point(10, 10)
$LegendPanel.Controls.Add($TotalSpaceLabel)

# Add Labels to simulate legend
$UsedSpaceLabel = New-Object System.Windows.Forms.Label
$UsedSpaceLabel.Size = "300,25"
$UsedSpaceLabel.Text = "Used Space"
$UsedSpaceLabel.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Bold)
$UsedSpaceLabel.ForeColor = [System.Drawing.Color]::Red   # Color corresponding to the "Used Space" part of the chart
$UsedSpaceLabel.Location = New-Object System.Drawing.Point(10, 40)
$LegendPanel.Controls.Add($UsedSpaceLabel)

$FreeSpaceLabel = New-Object System.Windows.Forms.Label
$FreeSpaceLabel.Size = "300,25"
$FreeSpaceLabel.Text = "Free Space"
$FreeSpaceLabel.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Bold)
$FreeSpaceLabel.ForeColor = [System.Drawing.Color]::Green  # Color corresponding to the "Free Space" part of the chart
$FreeSpaceLabel.Location = New-Object System.Drawing.Point(10, 70)
$LegendPanel.Controls.Add($FreeSpaceLabel)

$FolderSpaceLabel = New-Object System.Windows.Forms.Label
$FolderSpaceLabel.Size = "300,25"
$FolderSpaceLabel.Text = "Selected Folder Space"
$FolderSpaceLabel.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Bold)
$FolderSpaceLabel.ForeColor = [System.Drawing.Color]::Blue  # Color corresponding to the "Free Space" part of the chart
$FolderSpaceLabel.Location = New-Object System.Drawing.Point(10, 100)
$LegendPanel.Controls.Add($FolderSpaceLabel)

# Largest Files Label
$BigFilesLabel = New-Object System.Windows.Forms.Label
$BigFilesLabel.Location = "200,560"
$BigFilesLabel.Size = "300,25"
$BigFilesLabel.Font = New-Object System.Drawing.Font("Arial", 14,[System.Drawing.FontStyle]::Bold)
$BigFilesLabel.Text = "Largest Files"
$Form.Controls.Add($BigFilesLabel)

# Create the TextBox to display the largest files
$BigFiles = New-Object System.Windows.Forms.TextBox
$BigFiles.Multiline = $true
$BigFiles.ScrollBars = [System.Windows.Forms.ScrollBars]::Vertical
$BigFiles.Size = New-Object System.Drawing.Size(1000,250)
$BigFiles.Location = new-object System.Drawing.Size(20,600)
$BigFiles.Font = New-Object System.Drawing.Font("Arial", 12,[System.Drawing.FontStyle]::Regular)
$Form.Controls.Add($BigFiles)

# Function to calculate folder size (recursively)
Function Get-FolderSize {
    Param (
        [String]$FolderPath
    )
    
    $Size = 0
    Try {
        # Add all files in the folder and subfolders
        $Files = Get-ChildItem -Path $FolderPath -Recurse -File -ErrorAction SilentlyContinue
        Foreach ($File in $Files) {
            $Size += $File.Length
        }
    } Catch {
        Write-Host "Error calculating size for $FolderPath"
    }
    Return $Size
}

# Function to load folders into the TreeView recursively
Function Load-FolderTree {
    Param (
        [System.Windows.Forms.TreeNode]$ParentNode,
        [string]$path
    )

    # Create the node for the current directory
    $Node = New-Object System.Windows.Forms.TreeNode -ArgumentList (Get-Item $Path).Name
    $Node.Tag = $Path

    # Add the node to the parent node
    $ParentNode.Nodes.Add($Node)

    # Debugging: Print the current directory being processed
    Write-Host "Processing folder: $Path"

    # Try to load subfolders
    Try {
        $Subfolders = Get-ChildItem -Path $path -Directory -ErrorAction SilentlyContinue
        ForEach ($Dolder in $Subfolders) {
            # Recursively load subfolders
            Load-FolderTree -ParentNode $node -path $Folder.FullName
        }
    } catch {
        Write-Host "Error accessing folder: $path"
    }
}

# Function to update the pie chart based on selected folder
Function Update-PieChart {
    param (
        [String]$FolderPath
    )

    # Get the size of the selected folder (in bytes)
    $FolderSize = Get-FolderSize -FolderPath $FolderPath

	# Calculate Used, Free, and Total Space on Drive

	$DriveLetter = $SelectedDrive[0]
	$Drive = Get-PSDrive -Name $DriveLetter

        $FreeSpace = $Drive.Free
        $UsedSpace = $Drive.Used
        $TotalSpace = $Drive.Used + $Drive.Free

        # Update the pie chart with disk space and folder size
        $Series.Points.Clear()
      	$Series.Points.AddXY("Used Space", $UsedSpace)
	$Series.Points.AddXY("Free Space", $FreeSpace)  
        $Series.Points.AddXY("Folder Size", $FolderSize)

	$DisplayTotalSpace= $([math]::Round($TotalSpace / 1GB, 2))
	$DisplayUsedSpace= $([math]::Round($UsedSpace / 1GB, 2))
	$DisplayFreeSpace = $([math]::Round($FreeSpace / 1GB, 2))
	$DisplayFolderSpace= $([math]::Round($FolderSize / 1GB, 2))
	
	$TotalSpaceLabel.Text = "Total Disk Space: - $DisplayTotalSpace GB"
	$FreeSpaceLabel.Text = "Free Space - $DisplayFreeSpace GB"
	$UsedSpaceLabel.Text = "Used Space - $DisplayUsedSpace GB"        
        $FolderSpaceLabel.Text = "Selected Folder Space - $DisplayFolderSpace GB"

        # Set the chart colors
        $Series.Points[0].Color = [System.Drawing.Color]::FromArgb(255, 0, 0)  # Red for used space
        $Series.Points[1].Color = [System.Drawing.Color]::FromArgb(0, 255, 0)  # Green for free space
        $Series.Points[2].Color = [System.Drawing.Color]::FromArgb(0, 0, 255)  # Blue for folder size

}

# Function to find the ten largest files on the system
function Get-LargestFiles {
    # Search the entire C: drive for files (or another drive as necessary)
    $Files = Get-ChildItem -Path "$SelectedDrive\" -Recurse -File -ErrorAction SilentlyContinue

    # Sort the files by size and select the top 10
    $LargestFiles = $Files | Sort-Object Length -Descending | Select-Object -First 10

    # Format the result as a string
    $FileList = "Size `t`t File `r`n"
    ForEach ($File in $LargestFiles) {
        $FileList += "$([math]::Round($File.Length / 1GB, 2)) GB `t`t $($File.FullName) `r`n"
    }

    # Update the TextBox with the largest files
    $BigFiles.Text = $FileList
    $BigFiles.SelectionStart = 0
    $BigFiles.SelectionLength = 0
}

# Load the root directory 
$RootPath = "$SelectedDrive\"  # You can change this to another path

# Create the root node and add it to the TreeView
$RootNode = New-Object System.Windows.Forms.TreeNode -ArgumentList (Get-Item $RootPath).Name
$RootNode.Tag = $rootPath
$FolderTree.Nodes.Add($rootNode)

# Start loading subfolders for the root node
Load-FolderTree -ParentNode $RootNode -path $RootPath

# Call the function to display the ten largest files when the script runs
Get-LargestFiles

# Event handler for when a node is selected in the TreeView
$FolderTree.Add_AfterSelect({
    Param ($Sender, $E)
    
    # Get the selected folder path
    $SelectedNode = $E.Node
    $SelectedFolderPath = $SelectedNode.Tag

    # Update the pie chart with the size of the selected folder
    Update-PieChart -FolderPath $SelectedFolderPath
})

# Disable output to the console (suppress unwanted output)
[System.Windows.Forms.Application]::EnableVisualStyles()

# Ensure the form runs and appears
[System.Windows.Forms.Application]::Run($Form)
    

# Disable output to the console (suppress unwanted output)

[System.Windows.Forms.Application]::EnableVisualStyles()

# Ensure the form runs and appears

[System.Windows.Forms.Application]::Run($Form)

Related:How To Use .NET Properties and Methods in PowerShell

About the Author

Brien Posey

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.

https://brienposey.com/

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like