4
votes

Get-ChildItem -Recurse in powershell currently traverse a directory in level order fashion. Is there any way to traverse a directory in post-order way in Powershell?

I am trying to delete files which are older than certain times. and after deleting files, if subfolder is empty, delete that folder too. Right now am doing this.

$path = 'D:\Files'
Get-ChildItem -Path $path -Recurse | Where-Object {
(($_.LastWriteTime -lt (Get-Date).AddDays(-30)) -and ($_ -is [system.io.fileinfo]) )
} | Remove-Item 


Get-ChildItem -Path $path -Recurse | Where-Object {
($_ -is [System.IO.DirectoryInfo]) -and $_.CreationTime -lt (Get-Date).AddDays(-30) -and ((Get-ChildItem $_.FullName).Count -eq 0)
} | Remove-Item -Force

But I want to do it in a single command. Not as two different command.

2
Please edit the question and explain with more details what you are trying to do. A practical example, even in pseudocode, would be nice.vonPryz
what are you trying to achieve that would benefit from some other sequence?Lee_Dailey
Do you actually want to lookup the items in reverse order, or is simply re-sorting them after a regular get-childitem an option?marsze
Question has been updated.Shakhawat95
As an aside: in PSv3+ you can limit enumeration to files and directories with -File and -Directory, respectively. In an enumeration that comprises both types, $_.PSIsContainer can be used to identify directories.mklement0

2 Answers

5
votes

You could reverse the order of the items returned by Get-ChildItem with [Array]::Reverse

Full script:

$items = Get-ChildItem 'D:\Files' -Recurse
[Array]::Reverse($items)
$date = (Get-Date).AddDays(-30)
foreach ($item in $items) {
    if ($item.PSIsContainer) {
        if ($item.CreationTime -lt $date -and (Get-ChildItem $item.FullName).Count -eq 0) {
            Remove-Item $item.FullName
        }
    }
    elseif ($item.LastWriteTime -lt $date) {
        Remove-Item $item.FullName
    }
}
0
votes

I couldn't get the post order working properly with GCI, someone claimed it should, but it wasn't traversing depth first. Below is a naive implementation of the classic post order algorithm using the push directory and pop directory commands. Put your "actions" where Write-Host is.

function PostOrder($d){
  pushd $d
  $folders = Get-ChildItem .\ -Directory -Force
  foreach ($folder in $folders){
    PostOrder($folder)
  }
  popd 
  Write-Host $d.FullName
}

PostOrder("C:\myFolder")