0

I am trying to limit the recursion depth for a folder search script that I wrote. I am trying to limit to up to five levels deep

Essentially I want to get something like this:

h:\demo\1st level
h:\demo\1st level\2nd level
h:\demo\1st level\2nd level\3rd level
h:\demo\1st level\2nd level\3rd level\4th level\
h:\demo\1st level\2nd level\3rd level\4th level\5th level

Here is the code that I have:

function Get-ChildItemRecursive {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)]

        [string]$FullName,
        [Parameter(Mandatory=$false)]

        [int]$Depth = 0
    )

    Process {
        if ($Depth -ne 1) {
            $newDepth = if ($Depth -gt 1) { $Depth - 1 } else { $Depth }
            Get-ChildItem -Path $FullName -Directory |
                Get-ChildItemRecursive -Depth $newDepth
        }
        else {
            Get-ChildItem -Path $FullName -Directory
        }
        Get-ChildItem -Path $FullName -File
    }
}

Get-ChildItemRecursive -FullName 'H:\demo\' |
   Where {$_.PSIsContainer -eq $True} | select @{Name='Date Modified';
Expression = {$_.LastWriteTime.ToString('MM/dd/yyyy')}},
             @{Name='Owner';E=
                 {(($_.GetAccessControl().Owner.Split('\'))[1])}},
             FullName | Export-Csv 'H:\demo\scan1.csv' -NoTypeInformation

The output I am getting:

Get-ChildItemRecursive -FullName 'H:\demo\' |
    Where {$_.PSIsContainer -eq $True} | select   @{Name='Date Modified';
Expression = {$_.LastWriteTime.ToString('MM/dd/yyyy')}},
             @{Name='Owner';E=
                 {(($_.GetAccessControl().Owner.Split('\'))[1])}},
             FullName | Export-Csv 'H:\demo\scan1.csv' -NoTypeInformation

PS H:\> Get-ChildItemRecursive
cmdlet Get-ChildItemRecursive at command pipeline position 1
Supply values for the following parameters:
FullName: H:\demo\

Directory: H:\demo

Mode                LastWriteTime     Length Name

----                -------------     ------ ----

-a---         6/21/2017   4:12 PM     248472 lastrun.csv

-a---         6/26/2017  11:27 AM        706 demo1.csv

-a---         6/21/2017   1:38 PM       7861 4thrun06-21-17.csv

-a---         6/21/2017  11:50 AM       2182 firstrun06-21-17.csv

-a---         6/21/2017   2:41 PM       1334 demo.csv

-a---         6/21/2017  12:24 PM      20985 3rdrun06-21-17.csv

-a---         6/26/2017   2:24 PM          0 scan1.csv

-a---         6/21/2017   4:22 PM       3671 sort-parent-subfolder.csv

-a---         6/21/2017  12:25 PM       7298 2ndrun06-21-17.csv

-a---         6/22/2017   4:46 PM       4637 2ndfolderRun6-22-17.csv

-a---         6/22/2017  10:59 AM      28540 firstfolder.csv

-a---         6/22/2017   4:59 PM     104618 4thfolder.csv


PS H:\>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
russell
  • 25
  • 10
  • Why not just upgrade and use the `-depth` parameter? Otherwise, change your single quotes to double quotes. – Nick Jun 26 '17 at 13:12
  • @Nick that is only available in powershell 5 and my company wants to remain at 4. I tried changing to double quotes Get-ChildItem -Recurse -Path "H:\demo\*\*\*\*\*" but it does not seem to limit everything to level 5 folders – russell Jun 26 '17 at 13:12
  • @Nick I removed the wildcards and recurse, but its still not displaying appropriately. – russell Jun 26 '17 at 13:23

2 Answers2

3

You can't limit recursion depth for Get-ChildItem -Recurse in PowerShell v4 or earlier. The respective parameter was added with PowerShell v5:

-Depth

This parameter, added in Powershell 5.0 enables you to control the depth of recursion. You use both the -Recurse and the -Depth parameter to limit the recursion.

Type: UInt32
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False

And your attempt doesn't work, because -Path 'H:\demo\*\*\*\*\*' gets the folder contents from exactly 5 levels deep. It doesn't include content from above that level.

If you can't upgrade to PowerShell v5 you can implement a recursive function that calls Get-ChildItem without -Recurse. Something like this:

function Get-ChildItemRecursive {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [string]$FullName,
    [Parameter(Mandatory=$false)]
    [int]$Depth = 0
  )

  Process {
    if ($Depth -ne 1) {
      $newDepth = if ($Depth -gt 1) { $Depth - 1 } else { $Depth }
      Get-ChildItem -Path $FullName -Directory | Get-ChildItemRecursive -Depth $newDepth
    }
    Get-ChildItem -Path $FullName
  }
}

Get-ChildItemRecursive -FullName 'H:\demo' -Depth 5 |
    Where {$_.PSIsContainer -eq $True} |
    ...
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • this results in an infinite loop and does not search the exact path specified. can you show me how this code would work with my path and parameters? thank you. – russell Jun 26 '17 at 13:38
  • Thank you for that, but I am still confused as to how my folder path will work with this code. is there anyway you can add an example path? (e.g. H:\demo\..) Also, how will I be able to add these parameters: select @{Name='Date Modified'; Expression={$_.LastWriteTime.ToString('MM/dd/yyyy')}}, @{Name='Owner';E={(($_.GetAccessControl().Owner.Split('\'))[1])}}, FullName | Export-Csv 'H:\Main Scans\Folder scan\de.csv' -NoTypeInformation – russell Jun 26 '17 at 15:10
  • Replacing `Get-ChildItem` with `Get-ChildItemRecursive` in your code should suffice. But I just noticed that the code was missing a `Process {...}` block. See updated answer. – Ansgar Wiechers Jun 26 '17 at 15:47
  • I am getting a prompt stating "supply values for the following parameters: Fullname:" is there any way to bypass this? Also, If I input "h:/demo/" it doesn't properly display all the parameters. – russell Jun 26 '17 at 16:25
  • Here is the code that I have: `Get-ChildItemRecursive -FullName 'H:\demo' | Where {$_.PSIsContainer -eq $True} | select @{Name='Date Modified'; Expression={$_.LastWriteTime.ToString('MM/dd/yyyy')}},@{Name='Owner';E={(($_.GetAccessControl().Owner.Split('\'))[1])}}, FullName | Export-Csv 'H:\demo\scan1.csv' -NoTypeInformation` – russell Jun 26 '17 at 16:34
  • The code works fine for me. Please double-check that you didn't miss anything. – Ansgar Wiechers Jun 26 '17 at 17:59
  • I am correct to call the function without any variable attached? – russell Jun 26 '17 at 18:15
  • What variable? The function has a mandatory parameter `-FullName` and an optional parameter `-Depth`. When the latter is omitted recursion depth is unlimited. Please update your question with the code you currently have and describe what exactly doesn't work. – Ansgar Wiechers Jun 26 '17 at 18:18
  • This seemed to have worked! sorry about the confusion. Just one more note; the program seems to get the depth that is exactly specified in the [int]$Depth = 0 and does not go through depths 1 -5 – russell Jun 26 '17 at 21:36
  • You if you want limited recursion you need to call `Get-ChildItemRecursive` **with** the parameter `-Depth` initially. I thought that was rather obvious. – Ansgar Wiechers Jun 26 '17 at 21:40
  • is there anyway I can set it to go through depths 1 through 5; If I add the -depth 5 it will only display folders from that depth. – russell Jun 26 '17 at 21:56
  • If you want the folders into which the function recurses along with the files adjust the function as show in my updated answer. – Ansgar Wiechers Jun 26 '17 at 22:20
  • Thank you very much! sorry for being such an annoyance.. any resources that you would recommend I utilize in order to get a better understanding of powershell? Thank you again! – russell Jun 26 '17 at 23:46
-3

It's no so beautiful, but you can try this:

# First lvl
Get-ChildItem -Recurse -Path 'D:\Test' | Where {$_.PSIsContainer -eq $True} | select  @{Name='Date Modified'; Expression={$_.LastWriteTime.ToString('MM/dd/yyyy')}},  @{Name='Owner';E={(($_.GetAccessControl().Owner.Split('\'))[1])}}, @{Name='FullnameLvl0';E={(($_.Fullname.Split('\')[0] + "\" + $_.Fullname.Split('\')[1]))}} | add-content D:\Test\test.csv

# Sec lvl
Get-ChildItem -Recurse -Path 'D:\Test' | Where {$_.PSIsContainer -eq $True} | select  @{Name='Date Modified'; Expression={$_.LastWriteTime.ToString('MM/dd/yyyy')}},  @{Name='Owner';E={(($_.GetAccessControl().Owner.Split('\'))[1])}}, @{Name='FullnameLvl1';E={(($_.Fullname.Split('\')[0] + "\" + $_.Fullname.Split('\')[1])+ "\" + $_.Fullname.Split('\')[2])}} | add-content D:\Test\test.csv

#...etc
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vitaly
  • 75
  • 4