The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,860 other subscribers

Thanks Jaykul for explaining me a custom PowerShell script that acts like DU (DiskUsage).

Posted by jpluimers on 2014/06/17

Thanks Joel Bennett (aka Jaykul) from Huddled Masses for answering my Stack Overflow question PowerShell Get-DiskUsage CmdLet: how to list from a different drive/directory?

In addition to answering it, he also added a complete new and lighter implementation of that script explaining why it was lighter and what idioms to follow in PowerShell.

After reading his aswer, I was even more aware of these two things than I was before:

  • I should emphasize the importance of the object pipeline even more than I already did.
  • You should try to cut down on the dynamically instantiated objects. Like any language with heavy objects, they provide the huge benefit of fast development, but also an inherent cost.

I wasn’t aware you can put your own crafted objects into the pipeline in a very easy way. But you can:

You can take advantage of this in PowerShell 3+ using the PSCustomObject, or in 2.0 by using New-Object PSObject -Property (1.0 also has that, but has a more convoluted syntax).
Both methods act like anonymous types in C#, with the added benefit you can return it from a function: C# can’t do that. Heck, they come close to ExpandoObject.
In PowerShell 3.0 and higher, you really should use PSCustomObject as it is much faster, and that the order of properties is maintained in the hashtable. New-Object PSObject -Property in PowerShell 2.0 does not do that.

This is his new script:

function Get-Size {
  #.Synopsis
  #  Calculate the size of a folder on disk
  #.Description
  #  Recursively calculate the size of a folder on disk,
  #  outputting it's size, and that of all it's children,
  #  and optionally, all of their children
  param(
    [string]$root,
    # Show the size for each descendant recursively (otherwise, only immediate children)
    [switch]$recurse
  )
  # Get the full canonical FileSystem path:
  $root = Convert-Path $root

  $size = 0
  $files = 0
  $folders = 0

  $items = Get-ChildItem $root
  foreach($item in $items) {
    if($item.PSIsContainer) {
      # Call myself recursively to calculate subfolder size
      # Since we're streaming output as we go,
      #   we only use the last output of a recursive call
      #   because that's the summary object
      if($recurse) {
        Get-Size $item.FullName | Tee-Object -Variable subItems
        $subItem = $subItems[-1]
      } else {
        $subItem = Get-Size $item.FullName | Select -Last 1
      }

      # The (recursive) size of all subfolders gets added
      $size += $subItem.Size
      $folders += $subItem.Folders + 1
      $files += $subItem.Files
      Write-Output $subItem
    } else {
      $files += 1
      $size += $item.Length
    }
  }

  # in PS3, use the CustomObject trick to control the output order
  if($PSVersionTable.PSVersion -ge "3.0") {
    [PSCustomObject]@{
      Folders = $folders
      Files = $Files
      Size = $size
      Name = $root
    }
  } else {
    New-Object PSObject -Property @{
      Folders = $folders
      Files = $Files
      Size = $size
      Name = $root
    }
  }
}

Edit 20250114: a modified answer with PowerShell 2.0 backward compatibility by [Wayback/Archive] User Paul-André Panon – Stack Overflow is at the bottom of [Wayback/Archive] PowerShell Get-DiskUsage CmdLet: how to list from a different drive/directory? – Stack Overflow.

--jeroen

One Response to “Thanks Jaykul for explaining me a custom PowerShell script that acts like DU (DiskUsage).”

  1. […] Thanks Jaykul for ex… on .NET/C#/PowerShell: building .… […]

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.