Bertos
Bertos

Reputation: 63

How can I automatically delete older files based on their names?

I'm having an issue with a software generating many files. I can't control the generation of files, but I can handle them after. Files have this kind of name:

"RandomString".*ProjectNumber*.*Date*.*Time*.txt

For example:

1297729137.0004202.20180925.232147.txt

I want to keep for the same ProjectNumber, only the last generated TXT file.

Any idea how I can do that easily?

Upvotes: 0

Views: 244

Answers (3)

Mark Wragg
Mark Wragg

Reputation: 23355

I think this should meet your needs:

$Files = Get-ChildItem *.txt

$ProjectFiles = $Files | ForEach-Object {
    $FileName = $_.Name -Split '\.'
    [pscustomobject]@{
        Name          = $_.Fullname
        RandomString  = $FileName[0]
        ProjectNumber = $FileName[1]
        DateTime      = [datetime]::parseexact($FileName[2] + $FileName[3], 'yyyyMMddHHmmss', $null)
    }
}

$FilesToRemove = ($ProjectFiles | Group-Object 'ProjectNumber') | ForEach-Object {
    ($_.Group | Sort-Object DateTime -Descending | Select-Object -Skip 1).Name
} | Where-Object { $_ -ne $null }

$FilesToRemove | Remove-Item -WhatIf

This retrieves all the text files and then creates a new custom PowerShell object with the name of the file and the properties you've specified from the filename by splitting on the '.'. We convert the date and time strings into a datetime object by using the parseexact method.

We can then use this new object to group the files by the project number, and then go through each of those groups sorting the results by Date, skipping the first result (which should be the newest dated project file) and returning the name of all others.

Then we can remove those file names with Remove-Item. When you're happy it's doing what you expect, remove the -WhatIf.

Note that this code assumes:

  • Your directory only contains *.txt files with these files and no others
  • The files always have the filename pattern you specified
  • The datetime is always in the exact format you've specified, e.g two digit 24-hour etc.
  • You're running this on PowerShell version 3 or newer.

Upvotes: 2

Aacini
Aacini

Reputation: 67216

@echo off
setlocal EnableDelayedExpansion

rem Search files, keep the last one by project
for /F "tokens=1-4 delims=." %%a in ('dir /B *.txt') do (
   if "%%c%%d" gtr "!project[%%b]!" set "project[%%b]=%%c%%d"
)

rem Remove the rest of files
for /F "tokens=1-4 delims=." %%a in ('dir /B *.txt') do (
   if "%%c%%d" neq "!project[%%b]!" del "%%a.%%b.%%c.%%d.txt"
)

This method assume that just such a files exist in the folder; if not, just change the wild-card by *.*.*.*.txt

Upvotes: 3

user6811411
user6811411

Reputation:

A similar approach to Mark Wragg, but using

  • a Where-Object with a match and capture groups to separate the file name elements.
  • a Select-Object to append calculated porperties PN and DT for ProjectName and DateTime
  • grouping by ProjectName
  • unrolling the group, sorting by DateTime descending and skipping the first (newest) to keep it
  • removing the other with the -WhatIf option to just show what would be deleted.

Get-ChildItem *.txt | Where-Object Name -match '^(([^\.]+)\.){4}txt$' |
  Select-Object *,@{n='PN';e={$Matches[2]}},@{n='DT';e={$Matches[3]+$Matches[4]}} |
    Group-Object PN |
      ForEach-Object{ $_.Group | sort DT -desc | select -skip 1 | RM -Whatif }

Upvotes: 1

Related Questions