[PowerShell][Example][Resource] Finding File Size throughout a folder/subfolder using recursion.

[PowerShell][Example][Resource] Finding File Size throughout a folder/subfolder using recursion.

Disk management, is always a fun task. Trying to find why a disk is running out of space... so whats a quick way. Copy and paste below of course. I recommend saving this into a file called "FileSize.ps1", or just download the files from here: filesize.zip.

class SizeIndex{
    [float$Size
    [string] $CreationUnit
    [float$SizeInBytes
    [float$SizeInKB
    [float$SizeInMB
    [float$SizeInGB
    [void] SetByte ($value) {$this.SizeInBytes = $value}
    [void] SetKB   ($value) {$this.SizeInKB    = $value}
    [void] SetMB   ($value) {$this.SizeInMB    = $value}
    [void] SetGB   ($value) {$this.SizeInGB    = $value}
    [void] set([float]$size, [string] $unit) {
        $byte = 0;
        switch($unit){
            "Byte"     {$byte = $size}
            "B"        {$byte = $size}
            "KiloByte" {$byte = $size/1000}
            "KB"       {$byte = $size/1000}
            "MegaByte" {$byte = $size/1000000}
            "MB"       {$byte = $size/1000000}
            "GigaByte" {$byte = $size/1000000000}
            "GB"       {$byte = $size/1000000000}
        }
        $this.SetByte($byte)
        $this.SetKB($byte/1000)
        $this.SetMB($byte/1000000)
        $this.SetGB($byte/1000000000)
    }
}
$script:fileCount = 0
function Get-DirectorySize{
    [cmdletbinding()]
    param(
        [string] $Path,
        [Validateset("Byte","KiloByte","MegaByte", "GigaByte")]
        [string] $Unit,
        [bool]   $Recurse = $false,
        [bool]   $OutFile = $false,
        [string] $OutputFileName = "$((Get-Item -Path ".\" -Verbose).FullName)\DirectoryScanOutput.csv"
    )
    $directoryFiles = gci $Path
    foreach($directoryFile in $directoryFiles){
        if($directoryFile.attributes -eq "Directory"){
            if($recurse){
                get-directorySize -path $($directoryFile.FullName) -unit $Unit -recurse $Recurse -outfile $outfile -outputfilename $outputFileName
            }
        }else{
            $sizeIndex = [SizeIndex]::new()
            $sizeIndex.set($directoryFile.Length, "Byte")
            $directoryFile | Add-Member -MemberType NoteProperty -Name Unit -Value $Unit
            switch($unit){
                "Byte"     {$directoryFile | Add-Member -MemberType NoteProperty -Name Size -Value $sizeIndex.SizeInBytes}
                "KiloByte" {$directoryFile | Add-Member -MemberType NoteProperty -Name Size -Value $sizeIndex.SizeInKB}
                "MegaByte" {$directoryFile | Add-Member -MemberType NoteProperty -Name Size -Value $sizeIndex.SizeInMB}
                "GigaByte" {$directoryFile | Add-Member -MemberType NoteProperty -Name Size -Value $sizeIndex.SizeInGB}
            }
            $outputString = "$($directoryFile.Name); $($directoryFile.BaseName); $($directoryFile.Extension); $($directoryFile.Size); $($directoryFile.Unit); $($directoryFile.Directory)"
            Write-Verbose $outputString
            if($OutFile){
                $outputString | Out-file $OutputFileName -Append
            }
            $script:fileCount++
        }
    }
}

And then the usage:

. .\FileSize.ps1
$startTime = Get-Date
Get-DirectorySize -Path "C:\Users\rober\desktop" -Unit "MegaByte" -Recurse $true -OutFile $true -OutputFileName "C:\Users\rober\Desktop\PS Projects\DirectoryData.csv" -verbose
$endTime = Get-Date
$timeSpan = $endTime - $startTime
"File Count: $script:fileCount"
"StartTime: $startTime EndDate: $endTime RunTimeInMinutes: $($timeSpan.TotalMinutes)"

This will generate a file where you tell it to, and it will be seperated via semicolon (;). Use excel, hit the data tab, text to columns and poof you can sort add it up.. your call.

For those of you curious on whats going on... I created a class to handle different file sizes. By defualt, Get-ChildItem (GCI) gets size in bytes, but I created this class to force data to byte and then you can get whichever unit you'd like.

I perform the GCI and if recursion is set to true, if a directory is found (via the attributes of the file) we call the function with the new path, passing the current directory. This will continue until a folder had no directories, gets any file info then work its way back upwards until hitting the root folder that you specified in the first place... you know recursion. :)

This will allow you to output to a file or just use the -verbose flag (thanks to commandletbindings) to print it on screen (of course you can always do both).

To give you some expectation of how long this will run... I used the above example and here's the output [27k files in ~ 1 min]:

File Count: 27790
StartTime: 09/07/2017 23:49:39 EndDate: 09/07/2017 23:50:53 RunTimeInMinutes: 1.235082045

Happy Scripting!

To view or add a comment, sign in

More articles by Robert Waltzing

Explore content categories