Назад | Перейти на главную страницу

PowerShell фильтрует файлы по дате в имени

У меня за день много файлов с разными именами. Как я могу отфильтровать их по дате в их имени?

Например:

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

И мой фрагмент кода:

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

У меня есть фильтр регулярных выражений: \w+_(\d+)\.\w+, который возвращает мне дату в переменной $ Matches, но как я могу объединить их и вернуть список файлов с теми файлами, которые старше 7 дней?

Я понимаю, что это вопрос четырехлетней давности. Но я подумал, что добавлю новый ответ, поскольку в настоящее время нет других одобренных ответов.

Я бы сделал это так, чтобы разобрать дату на фактическую DateTime объект из имени файла. Тогда вы можете использовать обычные сравнения дат, а не сравнения строк. Самый распространенный способ сделать это - использовать Расчетная недвижимость как часть Select-Object заявление. В приведенном ниже примере мы добавляем вычисляемое свойство с именем ParsedDate к существующему выпуску.

$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) }

Регулярное выражение на самом деле делает вещи более сложными, чем это могло бы быть необходимо. Если все ваши файлы имеют одинаковый шаблон именования app_ <ДАТА> .log, вы можете пропустить регулярное выражение и упростить, позволив ParseExact делай всю работу вот так. Вам просто нужно экранировать буквальные символы в строке формата, заключив их в одинарные кавычки.

$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) }

Технически говоря, вы также можете выполнить синтаксический анализ даты внутри предложения Where и пропустить промежуточное предложение Select. Но я оставлю это в качестве упражнения для читателя.

Это не очень приятно, но работает! :)

$RetainedDays = 14

$ArchiveBoundary = (Get-Date).AddDays(-$RetainedDays).ToString('yyyyMMdd')

$ProcessFiles = Get-ChildItem -Path $RootPath -Recurse |
    Where-Object { ($_.BaseName -split '_|\.')[1] -lt $ArchiveBoundary }

Посмотрите, поможет ли это приблизиться к тому, что вы пытаетесь сделать.

$RootPath = "C:\temp"
$ProcessFiles = @()
$RetainedDays = 7
$Today = get-date -format yyyyMMdd
$FileNameRegex  = "\w+_(\d+)\.\w+"
foreach ($File in Get-ChildItem -Path $RootPath) {
   $match = [regex]::matches($File, $FileNameRegex )
   $FileNameDate = $match[0].Groups[1].Value
   if (($Today - $FileNameDate) -ge $RetainedDays) { $ProcessFiles += $File }
}
$ProcessFiles