Jump to content
Software FX Community

DrillDown part 1. Hierarchical data


Recommended Posts

To illustrate how you can drilldown into hierarchical data using PowerGadgets and PowerShell, we will try to build a map of any folder in your hard disk showing the total size of all its subdirectories. There are many full blown apps that do this but I hope that in the process you will learn a few PowerShell tricks and discover how to use drilldown in PowerGadgets.

Let's start building the script that populates our gadget. My first try resulted in a script called get-size.ps1 which looks like this. I have a scripts folder on my machine and this folder was added to the Path environment variable.

$items = get-childitem $args
foreach($item in $items) {
  if ($item -is [system.IO.DirectoryInfo]) {
  add-member -inputobject $item -membertype ScriptProperty -Name Length -value { $elem = get-childitem $this.FullName -include *.* -recurse | measure-object -sum length; if ($elem -eq $null) {return 0;} else {return $elem.Sum;} }
  write-output $item

The meat of the script is in the add-member call, we are adding a new property to the directoryinfo object called Length and its value is a script that when executed will return the size of all the files and subdirectories in it. Calculating the size of a folder is achieved by the following

get-childitem $this.FullName -include *.* -recurse | measure-object -sum length

This first approach has a big drawback, if you just execute get-foldersize the output will be identical to doing get-item, in order to see the result of the calculations you have to type get-foldersize | select Name,Length.

The reason for this is how PowerShell outputs data to the console but it also reveals an interesting feature, if you execute both commands on a big folder you will notice that get-foldersize is quick while get-foldersize | Select Name,Length is actually doing the calculations. This means that our code will only be executed on demand. Lazy evaluation is not important for this particular script but it could be prove to be a valuable feature in other scripts.

Let's tweak our script to make it easier to see its results

$items = get-childitem $args
foreach($item in $items) {
  if ($item -is [system.IO.DirectoryInfo]) {
  $obj = new-object System.Object
  add-member -inputobject $obj -membertype NoteProperty -Name Folder -value $item
  add-member -inputobject $obj -membertype ScriptProperty -Name Length -value { $elem = get-childitem $this.Folder.FullName -include *.* -recurse | measure-object -sum length; if ($elem -eq $null) {return 0;} else {return $elem.Sum;} }
  write-output $obj

This new version of our script is a little more verbose - note that we are now creating an empty object and adding 2 properties to it - but if you just type get-foldersize you will get the results you are looking for. Note that we are adding a property called Folder and we are returning the DirectoryInfo object, we are lucky enough that its ToString method just returns the name but we have all the DirectoryInfo properties at our disposal. This is a good compromise between showing relevant information when simply typing the command but still allowing full access to all folder properties, e.g. the following command will give you the name, total size and attributes of all the subdirectories.

get-foldersize | Select {$_.Folder.Name},Length,{$_.Folder.Mode}

Now we are ready to start interacting our script with PowerGadgets, the obvious command foldersize | out-chart will give you a bar chart showing the subdirectories sizes but you will not see any meaningful labels. This is due to how out-chart decides which properties should be plotted (any numerical properties although the algorithm is a little more complex than this) and which properties can be considered labels (any string properties). Because we decided that our Folder property will contain the full DirectoryInfo object, out-chart decides that it cannot be used as the label. Clearly this is something we can improve in future versions. For now you have to type the following

get-foldersize | out-chart -label Folder -value Length


Let's add drill down capabilities to this by using drilldown_parameter, this allows you to specify which parameter(s) to pass when drilling down, e.g. when you double click on a bar, in our case we want to pass the full name of the child subdirectory to our get-foldersize script so we will just say

get-foldersize | out-chart -label Folder -value Length -drilldown_parameter {$_.Folder.FullName}

If you execute this command in a folder with subdirectories you will notice that when you double click on a bar the chart refreshes to show the size of the subdirectories of the folder you clicked on. To get back to the previous chart you can right click on the background of the chart and select back. If you are using build 2585 or later you can even use your mouse back button to return to the previous chart. If you double click a folder with no subdirectories you will get "No Data Available".

Obviously full blown apps can provide many more features for this problem, but getting an interactive gadget that shows subdirectory sizes recursively with only a 9-liner PowerShell script and the PowerGadgets cmdlet certainly sounds promising.

There are several ways we can improve on the visualization of this gadget, a typical one would be to show folders with a specific condition -e.g. those bigger than 10MB in a different color. Note that the -condition_ parameter actually exposes many visual attributes so you can control the color used, whether point labels are visible, etc.

get-foldersize | out-chart -label Folder -value Length -drilldown_parameter {$_.Folder.FullName} -condition {$_.Length -gt 10MB} -condition_Color DarkRed


Up to this point everything I described here is officially supported so to make this blog post a little more valuable I would like to show a totally unsupported but nonetheless cool feature, squarified treemaps are sometimes used in this kind of scenarios as they are able to convey size comparisons in a way where screen real-state use is maximized. Even though PowerGadgets does not natively support this as a gallery type, it supports the concepts of gallery extensions, and one of the ones we wrote as a proof of concept is a treemap extension. To use this you need to check if ChartFX.WinForms.TreeMap.dll is present in your PowerGadgets folder.

get-foldersize | out-chart -label Folder -value Length -drilldown_parameter {$_.Folder.FullName} -gallery treemap


I hope this post will get you interested on what you can achieve when using drilldown, in a future post we will show how to drilldown to a different script and other drilldown features.


Link to comment
Share on other sites

  • Create New...