Directory list recursive parent and child within

Viewed 95

I would like to get a directory listing with -recurse but to show the sub directories right under the parent.

Here is what I tried:

Get-ChildItem -Directory -Depth 3 | Select-Object Fullname

The results show first top-level directories and only then level 2 and only then level 3

Example:

C:\Users\Moshe\onedrive\pictures\35mm_Film    (has no sub directories)
C:\Users\Moshe\onedrive\pictures\Camera imports
C:\Users\Moshe\onedrive\pictures\Camera Roll

and only then

C:\Users\Moshe\onedrive\pictures\Camera imports\Folder1
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder2
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder3

and then

C:\Users\Moshe\onedrive\pictures\Camera Roll\2014
C:\Users\Moshe\onedrive\pictures\Camera Roll\2016

I would like to get the list showing parent and right underneath its sub dir

For example:

C:\Users\Moshe\onedrive\pictures\35mm_Film    (has no sub directories)
C:\Users\Moshe\onedrive\pictures\Camera imports
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder1
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder2
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder3
C:\Users\Moshe\onedrive\pictures\Camera Roll
C:\Users\Moshe\onedrive\pictures\Camera Roll\2014
C:\Users\Moshe\onedrive\pictures\Camera Roll\2016

it will also be nice to have the count of files for each directory but not crucial

For example:

C:\Users\Moshe\onedrive\pictures\35mm_Film 100
C:\Users\Moshe\onedrive\pictures\Camera imports 0 (no files in the parent)
C:\Users\Moshe\onedrive\pictures\Camera imports\Folder1  20

etc

3 Answers

If you want to do this without the need of sorting afterwards the solution can be a bit cumbersome, you can either use a recursive function / script block or as shown in this example, with a Stack<T> and as optional you can use a class:

class Tree {
    [int] $Depth
    [string] $Path
    [int] $FileCount
    hidden [IO.DirectoryInfo] $Instance

    Tree ([IO.DirectoryInfo] $Directory, [int] $Depth) {
        $this.Instance = $Directory
        $this.Path     = $Directory.FullName
        $this.Depth    = $Depth
        $this.CountFiles()
    }

    [IO.DirectoryInfo[]] EnumerateDirectories() {
        return $this.Instance.EnumerateDirectories()
    }

    [void] CountFiles() {
        $this.FileCount = $this.Instance.GetFiles().Count
    }
}


$stack = [Collections.Generic.Stack[Tree]]::new()
# define max Depth here
$maxDepth = 3
# initial path here
$path = 'C:\Users\Moshe\onedrive\pictures'
# define what you want to skip here
$attrToSkip = [IO.FileAttributes] 'Hidden'
$stack.Push([Tree]::new($path, 0))

while($stack.Count) {
    $folder = $stack.Pop()

    # this conditions stops the loop
    $reachedMaxDepth  = $folder.Depth -gt $maxDepth
    # this condition skips Hidden folders, remove it if you want to show all
    $isHiddenorSystem = $folder.Instance.Attributes -band $attrToSkip

    if($reachedMaxDepth -or $isHiddenorSystem) {
        continue
    }

    $folder

    foreach($i in $folder.EnumerateDirectories()) {
        $stack.Push([Tree]::new($i, $folder.Depth + 1))
    }
}

To get the directories in that order you can use Sort-Object.

Example:

Get-ChildItem -Directory -recurse -Depth 3 | Select-Object Fullname | Sort-Object Fullname

This will give you the parent and their subfolders in order.

I took the example from malexander and added some of the Daniel example and came up with this

Get-ChildItem -Directory -recurse -Depth 3 | Select-Object Fullname | Sort-Object Fullname | % {$_.FullName + " " + (Get-ChildItem $_.FullName| Measure-Object).Count}

If understand correctly the Fullname is showing only once because it was piped to the % which shows both the name and the count.

Anyways, it gave me exactly what I needed.

Thanks to all

Related