├── .floo ├── ReadMe.md ├── TreeSize.Format.ps1xml ├── TreeSize.psd1 └── TreeSize.psm1 /.floo: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://floobits.com/Jaykul/TreeSize" 3 | } -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | This is just a Get-TreeSize function to show (recursively) how much space (files and) folders take up. I wrote it in a 3hr live-coding session on Floobits as an exercise for the [PowerShell virtual user group](http://PowerShell.slack.com) (for an invite visit http://slack.poshcode.org) 2 | 3 | Anyway, there's just one function and a format file. Please enjoy. 4 | 5 | To install: 6 | 7 | ```posh 8 | Install-Module -Name TreeSize 9 | ``` 10 | 11 | Example usage: 12 | 13 | ``` 14 | PS> Get-Treesize 15 | 16 | Localization\ 12021 17 | ├─ En-US\ 2025 18 | ├─ En\ 1339 19 | ``` 20 | 21 | ``` 22 | PS> Get-Treesize -ShowFiles 23 | 24 | Localization\ 12021 25 | ├─ Localization.psd1 6698 26 | ├─ En-US\ 2025 27 | ├─ UserSettings.psd1 1000 28 | ├─ Localization.psd1 958 29 | ├─ numbers.psd1 67 30 | ├─ UserSettings.psd1 1959 31 | ├─ En\ 1339 32 | ├─ UserSettings.psd1 1253 33 | ├─ numbers.psd1 86 34 | ``` 35 | 36 | ``` 37 | PS> Get-Treesize | Format-Custom 38 | 39 | Localization\ (11.74 KB) 40 | ├─ En-US\ (1.98 KB) 41 | ├─ En\ (1.31 KB) 42 | ``` -------------------------------------------------------------------------------- /TreeSize.Format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | System.IO.TreeView 6 | 7 | System.IO.TreeView 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | TreeName 17 | 18 | 19 | Length 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | TreeView 28 | 29 | System.IO.TreeView 30 | TreeView 31 | 32 | 33 | 34 | 35 | 36 | 37 | 4 38 | 39 | 40 | TreeName 41 | 42 | ( 43 | 44 | 45 | if($_.Length -gt 1TB) { 46 | "{0:N2} TB" -f ($_.Length/1TB) 47 | } elseif($_.Length -gt 1GB) { 48 | "{0:N2} GB" -f ($_.Length/1GB) 49 | } elseif($_.Length -gt 1MB) { 50 | "{0:N2} MB" -f ($_.Length/1MB) 51 | } elseif($_.Length -gt 1KB) { 52 | "{0:N2} KB" -f ($_.Length/1KB) 53 | } else { 54 | $_.Length 55 | } 56 | 57 | 58 | ) 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /TreeSize.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'TreeSize' 3 | # 4 | # Generated by: Joel 5 | # 6 | # Generated on: 8/12/2015 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'TreeSize.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '2.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '7c23eb22-93a3-4b2b-abcf-f6a33eec0adf' 19 | 20 | # Author of this module 21 | Author = 'Joel "Jaykul" Bennett' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'PoshCode' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2015 Joel Bennett. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | Description = 'Provides a Get-TreeSize command' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | PowerShellVersion = '5.0' # because I'm lazy 34 | 35 | # Type files (.ps1xml) to be loaded when importing this module 36 | # TypesToProcess = @() 37 | 38 | # Format files (.ps1xml) to be loaded when importing this module 39 | FormatsToProcess = 'TreeSize.Format.ps1xml' 40 | 41 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 42 | # NestedModules = @() 43 | 44 | # Functions to export from this module 45 | FunctionsToExport = 'Get-TreeSize' 46 | 47 | # Aliases to export from this module 48 | AliasesToExport = 'TreeSize' 49 | 50 | # List of all files packaged with this module 51 | FileList = @('TreeSize.ps1xml', 'TreeSize.psm1', 'TreeSize.psd1') 52 | 53 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 54 | PrivateData = @{ 55 | PSData = @{ 56 | # Tags applied to this module. These help with module discovery in online galleries. 57 | Tags = @("FileSystem", "TreeSize") 58 | 59 | # A URL to the license for this module. 60 | LicenseUri = 'http://opensource.org/licenses/ms-pl' 61 | 62 | # A URL to the main website for this project. 63 | ProjectUri = 'https://github.com/Jaykul/TreeSize' 64 | 65 | # A URL to an icon representing this module. 66 | # IconUri = '' 67 | 68 | # ReleaseNotes of this module 69 | ReleaseNotes = @" 70 | This is the second release, and it sorts the output by size. 71 | I also made the indent character settable, in case you want to use ascii "|--" 72 | "@ 73 | 74 | } # End of PSData hashtable 75 | 76 | } # End of PrivateData hashtable 77 | 78 | # HelpInfo URI of this module 79 | # HelpInfoURI = '' 80 | 81 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 82 | # DefaultCommandPrefix = '' 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /TreeSize.psm1: -------------------------------------------------------------------------------- 1 | # PowerShell 5 feature (oops, has to be the "first thing" in a script) 2 | # In PowerShell 4 we have to use Import-Namespace from the reflection module 3 | using namespace System.IO 4 | 5 | ## This is not working ... I guess we need a format file to show it right 6 | ## The objects appear to be typed correctly ( Get-Member shows them as "System.IO.TreeView" ) 7 | # Update-TypeData -TypeName "System.IO.TreeView" -DefaultDisplayProperty TreeName -DefaultDisplayPropertySet TreeName, Length -Force 8 | 9 | function Get-TreeSize { 10 | #.Synopsis 11 | # Recursively lists provider items and sums their lengths 12 | #.Description 13 | # The actual objects are the same file system objects you'd get from Get-ChildItem -Recurse 14 | # But with properties added to them like Depth and with Length calculated for the folders 15 | # Then a custom formmatter makes them come out like this: 16 | # 17 | # .Example 18 | # Get-Treesize 19 | # Localization\ 12021 20 | # |-- En-US\ 2025 21 | # |-- En\ 1339 22 | # .Example 23 | # Get-Treesize -ShowFiles 24 | # Localization\ 12021 25 | # |-- Localization.psd1 6698 26 | # |-- En-US\ 2025 27 | # |-- UserSettings.psd1 1000 28 | # |-- Localization.psd1 958 29 | # |-- numbers.psd1 67 30 | # |-- UserSettings.psd1 1959 31 | # |-- En\ 1339 32 | # |-- UserSettings.psd1 1253 33 | # |-- numbers.psd1 86 34 | # .Example 35 | # Get-Treesize | Format-Custom 36 | # 37 | # Localization\ (11.74 KB) 38 | # |-- En-US\ (1.98 KB) 39 | # |-- En\ (1.31 KB) 40 | 41 | [CmdletBinding()] 42 | param( 43 | # The root of the tree view 44 | [Parameter(ValueFromPipelineByPropertyName)] 45 | [Alias("PSPath")] 46 | $Path = $pwd, 47 | 48 | # Whether to show files or just folder in the resulting tree 49 | [Parameter()] 50 | [Switch]$ShowFiles, 51 | 52 | # How deep to start the indent (hypothetically for splitting up the work) 53 | # Defaults to the number of elements in $Path.Split("\") 54 | [int]$Depth = $((Convert-Path $Path).Split([Path]::DirectorySeparatorChar).Length), 55 | 56 | # Customize the TreeView 57 | $ChildIndicator = $(([char[]]@(0x251c, 0x2500, " ")) -join "") 58 | ) 59 | process { 60 | # I'm going to choose to show FileSystem paths here 61 | # Which means any PowerShell "PSDrive" will be lost 62 | # We could change that later ... 63 | $Local:Path = Convert-Path $Path 64 | $Local:Length = 0 65 | 66 | # Cache the recursive output so it comes out in the right order 67 | $Local:Children = @( 68 | switch(Get-ChildItem -Path $Local:Path -Force) { 69 | {$_ -is [DirectoryInfo]} { 70 | # Recurse! And don't forget to pass all the parameters down ... 71 | $Info = Get-TreeSize -Path $_.FullName -ShowFiles:$ShowFiles -Depth ($Depth + 1) 72 | # Running total ... 73 | $Local:Length += $Info[0].Length 74 | $Info 75 | } 76 | {$_ -is [FileInfo]} { 77 | # Running total ... 78 | $Local:Length += $_.Length 79 | if($ShowFiles) { $_ } 80 | } 81 | } 82 | ) 83 | 84 | # To allow us to sort the children by size, we need to collect them all so we can sort at each level of output 85 | # Thus, if we're not the root invocation, roll-up the children 86 | if(1 -lt (Get-PSCallStack | Where Command -eq $MyInvocation.MyCommand).Count) { 87 | Get-Item -Path $Local:Path | Add-Member NoteProperty Length $Local:Length -Force -Passthru | Add-Member NoteProperty Children $Local:Children -Passthru 88 | } else { 89 | # This just outputs items and their .Children, recursively, sorted by length... 90 | function UnrollChildren { 91 | param($Items) 92 | foreach($Item in @($Items)) { 93 | $Item 94 | if($Item.Children) { 95 | UnrollChildren ($Item.Children | Sort Length -Descending) 96 | } 97 | } 98 | } 99 | 100 | UnrollChildren (Get-Item -Path $Local:Path | Add-Member NoteProperty Length $Local:Length -Force -Passthru | Add-Member NoteProperty Children $Local:Children -Passthru) | 101 | ForEach-Object { $_.PSTypeNames.Insert(0, "System.IO.TreeView"); $_ } | 102 | Add-Member ScriptProperty Depth { $this.FullName.Split([Path]::DirectorySeparatorChar).Length } -Passthru -Force | 103 | # NOTE: Even though this is a ScriptProperty 104 | # We have to add it here, dynamically, instead of in a types file because we use $Depth 105 | Add-Member ScriptProperty "TreeName" { (" " * [Math]::Max(($this.Depth - $Depth -1), 0)) + $(if($this.Depth -ne $Depth){$ChildIndicator}) + $this.Name + $(if($this.PSIsContainer){"\"})} -Passthru -Force 106 | } 107 | } 108 | } 109 | 110 | Set-Alias TreeSize Get-TreeSize 111 | --------------------------------------------------------------------------------