Skip to content

Instantly share code, notes, and snippets.

@tunaworks
Last active March 18, 2021 14:42
Show Gist options
  • Save tunaworks/a1e303a060c83b7884cd72fbed0ec163 to your computer and use it in GitHub Desktop.
Save tunaworks/a1e303a060c83b7884cd72fbed0ec163 to your computer and use it in GitHub Desktop.
Gets the size and path of all subdirectories below a specied size, and option to delete them.
#Code progress:
# finds actual size of a folder
# finds all directories & sub-directories
# filters folder < minsize
# format size to corresponding denom (B,KB..etc)
# store each matched result as a custom object with multiple properties
# store each match in an array (Results)
# print Result array as formatted table on command line.
# to do:
# remove the actual filtered folders (*do this in the ForEach loop, not the array?
#or give confirmation dialog option idk)
# Parent Directory to find folders
$dirpath = "H:\Tutorial M3\Rock Band"
$logpath = "$PSScriptRoot\Logs\"
$logpath = -join($logpath, ($dirpath|split-path -leaf), ".txt")
# Maximum size of each folder (empty or non-empty)
# e.g Find/Delete all folders smaller than 5MB
$foldermaxsize = 5 # <- max size of each folder (e.g. 10 * 1MB = 10MB, 10 * 1KB = 10KB, etc)
$sizeunit = 1MB # <- size denominator (e.g. 1KB, 1MB, 1GB, etc)
$foldermaxsize = $foldermaxsize * $sizeunit
$Final = new-object PSObject -Property @{"Length"= 0; "Size"=0}
# PRINT FORMATTING (takes in bytes, formats it with appropriate size denom)
Function Format-Size{
[cmdletbinding()]
Param (
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline = $true)]
$Bytes
)
switch -Regex ([math]::truncate([math]::log($bytes,1024))) {
'^0' {"$bytes Bytes"}
'^1' {"{0:n2} KB" -f ($bytes / 1KB)}
'^2' {"{0:n2} MB" -f ($bytes / 1MB)}
'^3' {"{0:n2} GB" -f ($bytes / 1GB)}
'^4' {"{0:n2} TB" -f ($bytes / 1TB)}
Default {"{0:n2} PB" -f ($bytes / 1PB)}
}
}
$sizestring = Format-Size $foldermaxsize
# returns size of single folder by summing all items (recursive) inside
Function Get-FolderSize {
# allows cmd options
[cmdletbinding()]
Param (
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline = $true)]
$folderpath
)
$size = 0
Write-Information $folderpath
# calculate folder size and recurse as needed
Foreach ($file in $(gci -LiteralPath $folderpath -recurse -force)){
If (-not ($file.psiscontainer)) {
$size += $file.length
}
}
# return the value and go back to caller
return $size
}
# filter = returns boolean TRUE if foldersize (passed from pipeline) is lt $foldermaxsize
Function Filter-FolderSize{
[cmdletbinding()]
Param (
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline = $true)]
$foldersize
)
if ($foldersize -lt $foldermaxsize){
return $true
}else{
return $false
}
}
# Array containing filepaths of each directory (recursive) found within $dirpath
# gci = GetChildItem
$Folders = @(gci -LiteralPath $dirpath -Recurse | ?{ $_.PSIsContainer } | Select-Object -ExpandProperty FullName)
# Check for null results from cgi function
if ($Folders.length -eq 0) {
write-host " no folders."
} else {
# $Results = array of PSobjects containing (Size,folderpath)
$Result = @()
# $folder = full path of current folder
ForEach ($folder in $Folders){
# returns int size of Folder (by recursively summing all child filesize)
$curfoldersize = Get-FolderSize $folder
# returns boolean T/F
$curfilter = Filter-FolderSize $curfoldersize
# excludes parent dir from final pathname
$folder = $folder.Replace(($dirpath+"\"), "")
# add to $Results array
if ($curfilter){
$obj = new-object PSObject -Property @{"Size"= $curfoldersize; "Path"=$folder}
$Result += $obj
$Final.Size += $curfoldersize
$Final.Length +=1
}
}
# Result_Table formatted output
$Result_Table = $Result | Select-Object Size,Path | Format-Table `
-Property `
(@{Name=("Size"+ "(" + (Format-Size $sizeunit) + ")" );Expression={Format-Size($_.Size)};align='right'},`
@{Name='Path';Expression={$_.Path};align='left'}) `
Write-Output $Result_Table
#Write-Output $Result.Path $Final.Length (Format-Size $Final.size)
$title = 'Delete ' + $Final.Length + ' folders? (' + (Format-Size $Final.size) + ')'
$question = 'Y/N?'
$yes = New-Object System.Management.Automation.Host.ChoiceDescription '&Yes','Deletes selected
folders'
$no = New-Object System.Management.Automation.Host.ChoiceDescription '&No','Leaves folders untouched'
$options = [System.Management.Automation.Host.ChoiceDescription[]] ($Yes,$No)
$choice = $Host.UI.PromptForChoice($title,$question,$options,1)
if ($choice -eq 0) {
Write-Host 'confirmed'
Start-Transcript $logpath
ForEach($member in $Result){
$path = Join-Path -Path $dirpath -ChildPath $member.Path
$path = [wildcardpattern]::Escape($path)
Write-Output -join @($path,"(",$member.Size,")")
Remove-Item -Confirm:$false -Recurse $path
}
Stop-Transcript
} else {
Write-Host 'cancelled'
}
if ($Host.Name -eq "ConsoleHost")
{
Write-Host "Press any key to continue..."
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment