PowerShell filter files by date in name

filesfilterlog-filespowershell

I have many files with different names per day. How can I filter them by the date in their name?

For example:

app_20130505.log
app_20130506.log
app_20130507.log
app_20130508.log
app_20130509.log

And my code snippet:

$RetainedDays = 7
$FileNameRegex = "\w+_(\d+)\.\w+"
$ArchiveBoundary = $(Get-Date -Format yyyyMMdd) - $RetainedDays
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse |
    Where-Object { $_.Name -match $FileNameRegex }

I have regex filter for it : \w+_(\d+)\.\w+, that gives me back the date in $Matches variable, but how can I combine them, and get back the file list, with those files, which older than 7 days?

Best Answer

I realize this is a 4 year old question at this point. But I figured I'd add a new answer since there are currently no other up-voted ones.

The way I'd go about this is parsing the date into an actual DateTime object from the file name. Then you can use normal date comparisons rather than string comparisons. The most common way to do this is using a Calculated Property as part of a Select-Object statement. In the example below, we add a calculated property called ParsedDate to the existing output.

$RetainedDays = 7
$FileNameRegex = "\w+_(\d+)\.\w+"
$culture = [System.Globalization.CultureInfo]::InvariantCulture
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse | 
  Select-Object *,@{
    L='ParsedDate';
    E={ if ($_.Name -match $FileNameRegex) { 
      $strDate = $matches[1];
      [DateTime]::ParseExact($strDate,"yyyyMMdd",$culture)
    }
  }
} | Where { $_.ParsedDate -lt (Get-Date).AddDays(-$RetainedDays) }

The regular expression actually makes things more complicated than they might need to be though. If your files all have the exact same naming pattern of app_<DATE>.log, you can skip the Regex and simplify by letting ParseExact do all the work like this. You just need to escape the literal characters in the format string by surrounding them with single quotes.

$RetainedDays = 7
$culture = [System.Globalization.CultureInfo]::InvariantCulture
$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse | Select FullName,@{
  L='ParsedDate';
  E={ [DateTime]::ParseExact($_.Name,"'app_'yyyyMMdd'.log'",$culture) }
} | Where { $_.ParsedDate -lt (Get-Date).AddDays(-$RetainedDays) }

Technically speaking, you could also do the date parsing inside the Where clause and skip the intermediate Select clause. But I'll leave that as an exercise for the reader.

Related Topic