public/Get-PSTree.ps1
using namespace System.IO using namespace System.Collections.Generic <# .SYNOPSIS tree like function for PowerShell .DESCRIPTION PowerShell function that intends to emulate the tree command with added functionality to calculate the folders size as well as recursive folders size. .PARAMETER LiteralPath Absolute or relative folder path. .PARAMETER Depth Determines the number of subdirectory levels that are included in the recursion. .PARAMETER Recurse Gets the items in the specified locations and in all child items of the locations. .PARAMETER Force Gets items that otherwise can't be accessed by the user, such as hidden or system files. .PARAMETER Directory Displays Directories only. .PARAMETER RecursiveSize Displays the recursive Size of Folders. .INPUTS System.String You can pipe a string that contains a path to Get-PSTree. Can take pipeline input from cmdlets that outputs System.IO.DirectoryInfo. .OUTPUTS Object[], PSTreeDirectory, PSTreeFile .EXAMPLE Get-PSTree Get hierarchy of the current Directory with default parameters (`-Depth 3`) .EXAMPLE Get-PSTree -Directory -Recurse Get hierarchy of the current Directory recursively displaying only Folders .EXAMPLE Get-PSTree -Depth 2 -Force Get hierarchy of the current Directory 2 levels deep and displaying hidden Folders .EXAMPLE Get-PSTree -Depth 2 -RecursiveSize -Directory Get hierarchy 2 levels deep displaying only Folders with their recursive size .LINK https://github.com/santisq/PSTree #> function Get-PSTree { [cmdletbinding(DefaultParameterSetName = 'Depth')] [OutputType('PSTreeDirectory', 'PSTreeFile')] param( [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('PSPath')] [string] $LiteralPath = $PWD.Path, [Parameter(ParameterSetName = 'Depth', Position = 1)] [int] $Depth = 3, [Parameter(ParameterSetName = 'Recurse', Position = 1)] [switch] $Recurse, [Parameter()] [switch] $Force, [Parameter()] [switch] $Directory, [Parameter()] [switch] $RecursiveSize ) begin { $isRecursive = $RecursiveSize.IsPresent -or $Recurse.IsPresent } process { try { $absolutePath = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($LiteralPath) if([File]::GetAttributes($absolutePath).HasFlag([FileAttributes]::Archive)) { return [PSTreeFile]::new($absolutePath, 0) } if($absolutePath -ne [Path]::GetPathRoot($absolutePath)) { $absolutePath = $absolutePath.TrimEnd([Path]::DirectorySeparatorChar) } foreach($item in $PSCmdlet.InvokeProvider.Item.Get($absolutePath, $Force.IsPresent, $true)) { $indexer = @{} $stack = [Stack[PSTreeDirectory]]::new() $stack.Push([PSTreeDirectory]::new($item, 0)) $output = while($stack.Count) { $next = $stack.Pop() $level = $next.Depth + 1 $size = 0 try { $enum = $next.EnumerateFileSystemInfos() } catch { if($Recurse.IsPresent -or $next.Depth -le $Depth) { $next } $PSCmdlet.WriteError($_) continue } $keepProcessing = $isRecursive -or $level -le $Depth $items = foreach($item in $enum) { if(-not $Force.IsPresent -and $item.Attributes.HasFlag([FileAttributes]::Hidden)) { continue } if($item -is [FileInfo]) { $size += $item.Length if($Directory.IsPresent) { continue } [PSTreeFile]::new($item, $level) continue } if($keepProcessing) { $stack.Push([PSTreeDirectory]::new($item, $level)) } } $next.SetSize($size) $indexer[$next.FullName] = $next if($RecursiveSize.IsPresent) { foreach($parent in $next.GetParents($indexer)) { $indexer[$parent].AddSize($size) } } if($Recurse.IsPresent -or $next.Depth -le $Depth) { $next if($items -and $Recurse.IsPresent -or $level -le $Depth) { $items } } } [PSTreeStatic]::DrawTree($output, 'Hierarchy', 'Depth') } } catch { $PSCmdlet.WriteError($_) } } } |