3

C:\Temp\ifc has about 297 folders inside it with roughly 4.1 million files spread amongst them.

Using a script I found elsewhere on this site, I wrote the following to delete all 'files' which are older than 1 hour.

$TargetFolder = “C:\Temp\ifc”
$NumberRange = "-1"
Get-ChildItem $TargetFolder -Recurse | Where {$_.lastwritetime -lt (Get-Date).AddHours($NumberRange)} | Remove-Item

The problem I am having is that it is deleting the sub-folders as well (if these folders end up with no files in them).

What can I add to this so that it leaves the folder structure in place?

Many Thanks.

Nic
  • 13,425
  • 17
  • 61
  • 104

1 Answers1

6

You could add an additional where clause to ignore folders like this:

Where-Object{!($_.PSIsContainer)}

In the code snippet above;

  • ! means not,
  • $_ means current value of object in the pipe,
  • PSIsContainer is a property of the current object that returns true or false depending on if it is a folder or not.

So !($_.PSIsContainer) means current value of object in pipe is not a folder,
which is evaluated by Where-Object{}

Then your script would be like this:

$TargetFolder = “C:\Temp\ifc\”
$NumberRange = "-1"
Get-ChildItem $TargetFolder -Recurse | Where-Object{!($_.PSIsContainer)} | Where {$_.lastwritetime -lt (Get-Date).AddHours($NumberRange)} | Remove-Item

Another approach is to ignore the folders at the call to Get-ChildItem using the -File parameter like this:

$TargetFolder = “C:\Temp\ifc\”
$NumberRange = "-1"
Get-ChildItem $TargetFolder -File -Recurse | Where {$_.lastwritetime -lt (Get-Date).AddHours($NumberRange)} | Remove-Item

This approach has the benefit of returning the file objects at a sooner point in the execution cycle and making the command line shorter. Depending on the number of objects in the path, this may also have a measurable speed improvement.

Tim Penner
  • 1,889
  • 14
  • 22
  • 1
    Or, if you've a recentish Powershell, [`Get-ChildItem $TargetFolder -Recurse -File ...`](https://technet.microsoft.com/en-us/library/hh847897(v=wps.620).aspx) so you can get files only before you hit the pipeline. – jscott Mar 06 '16 at 01:28
  • Where-Object{!($_.PSIsContainer)} worked perfectly, not sure what it means so must go do some Googling :) – Gareth Doherty Mar 06 '16 at 21:53
  • `!` means `not`, `$_` means current value of object in the pipe, `PSIsContainer` means is a folder. So `!($_.PSIsContainer)` means current value of object in pipe is not a folder which is fed into `Where-Object{}` – Tim Penner Mar 06 '16 at 22:03
  • i expanded the answer a bit, i hope this makes things more clear – Tim Penner Mar 06 '16 at 22:20
  • Remember that in v2 or v3, the Get-ChildItem cmdLet added switches "-file" and "-directory". Easier to type than "where {$_.psIsContainer -eq $something }" – Clayton Mar 07 '16 at 14:44