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






Hiding email behind a 30x redirect. « The Wiert Corner – irregular stream of stuff said
[…] Thanks Jaykul for ex… on .NET/C#/PowerShell: building .… […]