Calculating Folder Size Recursively with PowerShell

In an effort to keep my techie skills up to date, and to better live by my mantra of "GUIs Lie", I've undertaken an effort to use command-line tools and scripts in my personal computing.

Since I mostly use Windows on my home machine, laptop, and my workstation at the office, that means Microsoft PowerShell.

Since I'm low on space on my file server, I'm always looking to figure out which folders are using up disk space. I've got some ideas on a script I'd like to run which generates a report of disk utilization by folder. As a starting point, I've written this working, but horribly inefficient, script to recursively look through the folder structure, calculating the disk space used by every file in the location specified.

I know I could do this easier by using the -Recursive switch to the Get-ChildItems cmdlet, but I wanted to do it the hard way for a few reasons.

Anyhow, this is just a work-in-progress / proof-of-concept. Invoke the getFolderSize function passing in a string containing the location of the folder you want to measure, as well as the optional -v (verbose) and -h (human readable) parameters.


Function CalculateFolderSize ([parameter(Mandatory=$true)][string]$Location, [alias("v")][string]$Wordy)
{

# Initialize Variables
$Counter = 0
$FolderSize = 0
#stupid workaround as I can't define a switched param called "verbose"
$Verbose = $Wordy

# Create an array of "child" items in $Location
$ChildItems = Get-ChildItem -Path $Location

If ($Verbose -eq $true) {Write-Host "There are" $ChildItems.length "items to process."}

Foreach ($Item in $ChildItems)
{

$Counter = $Counter + 1
If ($Verbose -eq $true) {Write-Host "`n`nProcessing Item #" $Counter "," $Item.Name ", located in" $Location "."}

If ($Verbose -eq $true) {Write-Host "Before Processing" $Item.Name "The FolderSize was" $FolderSize}

If ($Item.Length -ge 0)
{
$FolderSize = $FolderSize + $Item.Length
If ($Verbose -eq $true) {Write-host "The FolderSize is now " $FolderSize}
}
else
{

If ($Verbose -eq $true) {Write-Host "I Will now recurse based on " $Item.FullName}

# if $Item ChildIttems is not null, then recurse. Otherwise, don't bother, it's empty.
$ChildItems = Get-ChildItem -Path $Item.FullName
if ($ChildItems.length -ge 0)
{
If ($Verbose -eq $true) {Write-Host "`nFound" $ChildItems.length " items. Proceeding to recurse."}
$FolderSize = CalculateFolderSize $Item.FullName $Wordy
}
else
{
If ($Verbose -eq $true) {Write-Host $Item.Fullname "is empty. Recursion cancelled.`n"}
}
}

}


#Return Total The Size of $Location
Return $FolderSize

}

Function GetFolderSize ([parameter(Mandatory=$true)][string]$Location, [alias("v")][switch]$Wordy, [alias("h")][switch]$Human)
{
# Initialize Variables
$Counter = 0
$FolderSize = 0
$Verbose = $Wordy #stupid workaround as I can't define a switched param called "verbose"

If ($Verbose -eq $true) {Write-Host "`nGetFolderSize invoked with:" $Location $Wordy $Human".`n"}


$FolderSize = calculateFolderSize $Location -Wordy $Wordy

#Format for human readability
if ($Human = $true)
{
If ($Verbose -eq $true) {Write-Host "`nInvoking Human Readability. Before:" $FolderSize}

if (($FolderSize / 1kb) -lt 1)
{
$FolderSize = [string]([math]::round($FolderSize, 2)) + "B"
}
elseif (($FolderSize / 1mb) -lt 1)
{
#Return KB
$FolderSize = [string]([math]::round($FolderSize / 1kb, 2)) + "KB"
}
elseif (($FolderSize / 1gb) -lt 1)
{
#Return MB
$FolderSize = [string]([math]::round($FolderSize / 1mb, 2)) + "MB"
}
elseif (($FolderSize / 1tb) -lt 1)
{
#Return GB
$FolderSize = [string]([math]::round($FolderSize / 1gb, 2)) + "GB"
}
else
{
#Return TB
$FolderSize = [string]([math]::round($FolderSize / 1tb, 2)) + "TB"
}

If ($Verbose -eq $true) {Write-Host "After:" $FolderSize "`n"}
}


return $FolderSize

}


# Sample Code to invoke the functions
$Path = "d:\"

$FolderSize = GetFolderSize $Path -h
Write-Host "The Total size of " $Path "is:" $FolderSize "`n`n"


No comments:

Post a Comment