Public/Remove-ALHOldFile.ps1
<#PSScriptInfo
.VERSION 2.2.0 .GUID ef26e9d5-cfb8-4cb8-bda5-b0b03888ca61 .AUTHOR Dieter Koch .COMPANYNAME .COPYRIGHT (c) 2021-2023 Dieter Koch .TAGS .LICENSEURI https://github.com/admins-little-helper/ALH/blob/main/LICENSE .PROJECTURI https://github.com/admins-little-helper/ALH .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES 1.0.0 - Initial Release 1.1.0 - Added support for -WhatIf parameter - Added and corrected verbose/error messages in case path is/is not accessible. 1.2.0 - Changed parameter '-Path' type from string to an array of strings to allow specifing multiple paths. - Added parameter '-Recurse' to be able to deal with subfolders of the given path(s). - Added parameter '-IncludeHiddenAndSystemFiles' to include hidden or system files in the search. - Added parameter '-KeepOldest' to reverse the files to keep sort order based on a file's 'LastWriteTime' property. - Added parameter '-Start' to be able to limit the scope of the file search based on a file's 'LastWriteTime' property. - Added parameter '-End' to be able to limit the scope of the file search based on a file's 'LastWriteTime' property. - Added parameter '-TimeSpan' to be able to limit the scope of the file search based on a file's 'LastWriteTime' property. TimeSpan is an alternative to parameters -Start and -End. - Added parameter '-RemoveAllOlderThanStart' to be able to remove all files matching the filename pattern before the given Start date/time. This is intended to use for cleaning up all older files than a given Start date/time and therefore only keep files for a given time range. - Added parameter '-RemoveAllNewerThanEnd' as opposite to '-RemoveAllOlderThanStart'. 1.2.1 - Updated description in examples to be more precise and added another example. 2.0.0 - Renamed function and file from Clear-FileHistory to Remove-ALHOldFile. 2.1.0 - Made function public instead of private within ALH module. 2.2.0 - Made script accept values for paramter Path from pipeline. #> <# .DESCRIPTION Contains function to clean up old files of a given filename pattern. #> function Remove-ALHOldFile { <# .SYNOPSIS A PowerShell function to remove old files in a given folder. .DESCRIPTION A PowerShell function to remove old files of a given filename pattern in a given folder. It's also possible to specify either start and end date/time or a timespan to limit the search results to files within that time range (based on LastWriteTime of the file). This is can be used for example to clean up old logfiles. .PARAMETER Path One or more folder paths to search in. The file search is executed for each individual folder. .PARAMETER FileNamePattern One or more filter strings used to search for filename. Accepts * and ? for wildcards (same as Get-ChildItem). .PARAMETER NumOfFilesToKeep The number of (newest) files to keep. If ommited, all files will be kept. All older (or newer in case '-KeepOldest' is specified) files within the defined scope (=matching FileNamePattern and time range) will be deleted. .PARAMETER Recurse If specified, the specified path(s) are processed recursively. The file search still is done for each individual folder. .PARAMETER KeepOldest If specified, the function will keep the oldest number of files defined by 'NumOfFilesToKeep', instead of the newest. .PARAMETER IncludeHiddenAndSystemFiles If specified, the file search will include hidden and system files (equal to 'Get-ChildItem -Force') .PARAMETER TimeSpan If specified, the file search will only cover files in the given time range calculated from current date/time backwards. .PARAMETER Start If specified, the file search will only include files with LastWriteTime newer than Start. If ommited, the Start will be set to earliest possible date/time (-Year 1 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0) .PARAMETER End If specified, the file search will only include files with LastWriteTime older than End. If ommitted, the current date/time will be used instead. .PARAMETER RemoveAllOlderThanStart If specified, *ALL* files matching the filter string(s), and older than the specified Start date/time will be deleted. .PARAMETER RemoveAllNewerThanEnd If specified, *ALL* files matching the filter string(s), and newer than the specified End date/time will be deleted. .EXAMPLE Remove-ALHOldFile -Path "C:\MyScript" -FileNamePattern "ReportFile*" -NumOfFilesToKeep 14 -Verbose Delete files in directory C:\MyScript with pattern "ReportFile*". Keep the newest 14 files and delete all older. .EXAMPLE Remove-ALHOldFile -Path "C:\MyScript" -FileNamePattern "ReportFile*" -NumOfFilesToKeep 14 -TimeSpan (New-TimeSpan -Days 14) -RemoveAllOlderThanStart -Verbose Delete files in directory C:\MyScript with pattern "ReportFile*". Keep only the newest 3 files last modified within the last 14 days and delete all older. .EXAMPLE Remove-ALHOldFile -Path "C:\MyScript" -FileNamePattern "ReportFile*" -NumOfFilesToKeep 14 -TimeSpan (New-TimeSpan -Days 14) -RemoveAllOlderThanStart -Recurse -Verbose Delete files in directory C:\MyScript and all subdirectories with pattern "ReportFile*". Keep only the newest 3 files last modified within the last 14 days and delete all older. .EXAMPLE Remove-ALHOldFile -Path "C:\MyScript" -FileNamePattern "ReportFile*" -NumOfFilesToKeep 14 -Start (Get-Date).AddDays(-21) End (Get-Date).AddDays(-14) -Verbose Delete files in directory C:\MyScript with pattern "ReportFile*". Keep the newest 2 files modified between 21 and 14 days ago and delete all older file in the same time range. .EXAMPLE Remove-ALHOldFile -Path "C:\MyScript","C:\MyOtherScript" -FileNamePattern "LogFile*.txt" -NumOfFilesToKeep 14 -TimeSpan (New-TimeSpan -Days 14) -RemoveAllOlderThanStart -Verbose Delete files in directory C:\MyScript and C:\MyOtherScript with pattern "LogFile*.txt". Keep only the newest 3 files last modified within the last 14 days and delete all older. .EXAMPLE 14..1 | ForEach-Object { Remove-ALHOldFile -Path "C:\MyScript\Log" -FileNamePattern "LogFile*.txt" -NumOfFilesToKeep 2 -Start (Get-Date).AddDays($_ *-1) -End (Get-Date).AddDays(($_ - 1) *-1) -Verbose } # Then remove all files older than 14 days Remove-ALHOldFile -Path "C:\MyScript\Log" -FileNamePattern "LogFile*.txt" -NumOfFilesToKeep 0 -End (Get-Date).AddDays(-14) -Verbose Keep newest 2 "Logfile*.txt" files for each day within the last 14 days in folder C:\MyScripts\Log .INPUTS System.String .OUTPUTS Nothing .NOTES Author: Dieter Koch Email: diko@admins-little-helper.de .LINK https://github.com/admins-little-helper/ALH/blob/main/Help/Remove-ALHOldFile.txt #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParametersetName = "default")] param( [ValidateNotNullOrEmpty()] [Parameter(ValueFromPipeline = $true, HelpMessage = 'Enter one or more path names', Position = 0)] [string[]] $Path, [Parameter(Mandatory = $true, HelpMessage = 'Enter filter pattern')] [string[]] $FileNamePattern, [Parameter(Mandatory = $false, HelpMessage = 'Enter number of files to keep for all files matching pattern and timespan/start/end')] [int16] $NumOfFilesToKeep = -1, [switch] $Recurse, [switch] $KeepOldest, [switch] $IncludeHiddenAndSystemFiles, [Parameter(Mandatory = $true, ParameterSetName = "CoverTimeSpan")] [timespan] $TimeSpan, [Parameter(Mandatory = $false, ParameterSetName = "CoverStartEnd")] [datetime] $Start, [Parameter(Mandatory = $false, ParameterSetName = "CoverStartEnd")] [datetime] $End, [Parameter(Mandatory = $false, ParameterSetName = 'CoverTimeSpan')] [Parameter(Mandatory = $false, ParameterSetName = 'CoverStartEnd')] [switch] $RemoveAllOlderThanStart, [Parameter(Mandatory = $false, ParameterSetName = 'CoverTimeSpan')] [Parameter(Mandatory = $false, ParameterSetName = 'CoverStartEnd')] [switch] $RemoveAllNewerThanEnd ) begin { } process { Write-Verbose -Message "Checking if path exists and is accessible" [array]$FoldersToSearchIn = foreach ($SinglePath in $Path) { if (Test-Path -Path $SinglePath -PathType Container) { Write-Verbose -Message "Path is a directory, exists and is accessible: $SinglePath" [array]$FolderList = Get-Item -Path $SinglePath if ($Recurse.IsPresent) { $FolderList = $FolderList + (Get-ChildItem -Path $SinglePath -Recurse -Directory) } Write-Verbose -Message "Number of folders to check: $(($FolderList | Measure-Object).Count)" Write-Verbose -Message "Folders to check: " foreach ($FolderItem in $FolderList) { Write-Verbose -Message " --> $($FolderItem.FullName)" } } else { Write-Warning -Message "Path is not a directory, does not exist or is not accessible: $SinglePath" } $FolderList } if ($null -eq $FoldersToSearchIn -or ($FoldersToSearchIn | Measure-Object).Count -eq 0) { Write-Error -Message "No valid path specified. Stopping process." break } if ($Start -gt (Get-Date)) { Write-Error -Message "Start is in future. Stopping process." break } if ($null -ne $TimeSpan) { Write-Verbose -Message "Timespan specified. Calculating start date/time based on timespan from now on backwards." $Start = (Get-Date).AddTicks($TimeSpan.Ticks) } if ($null -eq $Start) { Write-Verbose -Message "Start date/time not specified. Setting it to earliest possible time." $Start = Get-Date -Year 1 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0 } if ($null -eq $End) { Write-Verbose -Message "End date/time not specified. Setting it to current date/time." $End = Get-Date } if ($Start -gt $End) { Write-Error -Message "Specified Start date/time is greater than End date/time. Stopping process." break } if ($NumOfFilesToKeep -le -1) { Write-Verbose -Message "No files will be deleted." } else { Write-Verbose -Message "Start date/time: $Start" Write-Verbose -Message "End date/time: $End" foreach ($Folder in $FoldersToSearchIn) { $FilesToDelete = $null foreach ($pattern in $FileNamePattern) { Write-Verbose -Message "Searching files with pattern '$pattern' in folder $($Folder.FullName)" [array]$FilesFoundByPattern = Get-ChildItem -Path $Folder.FullName -Directory:$false -Filter $pattern -Force:$IncludeHiddenAndSystemFiles.IsPresent $NumFilesFoundMatchingPattern = ($FilesFoundByPattern | Measure-Object).Count Write-Verbose -Message "Number of files found matching pattern: $NumFilesFoundMatchingPattern in folder $($Folder.FullName)" [array]$FilesAlsoMatchingTimeSpan = $FilesFoundByPattern.where({ $_.LastWriteTime -ge $Start -and $_.LastWriteTime -le $End }) $NumFilesFoundTotal = ($FilesAlsoMatchingTimeSpan | Measure-Object).Count Write-Verbose -Message "Number of files found matching pattern and given timespan/start/end: $NumFilesFoundTotal in folder $($Folder.FullName)" $NumFilesToDelete = $NumFilesFoundTotal - $NumOfFilesToKeep if ($NumFilesToDelete -gt 0) { Write-Verbose -Message "Number of old files to delete: $NumFilesToDelete" [array]$FilesToDelete = $FilesAlsoMatchingTimeSpan | Sort-Object -Property LastWriteTime -Descending:$($true -and $KeepOldest.IsPresent) | Select-Object -First $NumFilesToDelete } else { Write-Verbose -Message "Number of files to keep is greater than files found - nothing to delete within timespan for search pattern." } if ($RemoveAllOlderThanStart.IsPresent) { Write-Verbose -Message "Parameter 'RemoveAllOlderThanStart' specified. Adding ALL files older than start date/time to delete list." $AdditionalFilesOlderThanStart = $FilesFoundByPattern.where({ $_.LastWriteTime -lt $Start }) $FilesToDelete = $FilesToDelete + $AdditionalFilesOlderThanStart Write-Verbose -Message "Number of files found to be older thand start date/time: $(($AdditionalFilesOlderThanStart | Measure-Object).Count) in folder $($Folder.FullName)" } if ($RemoveAllNewerThanEnd.IsPresent) { Write-Verbose -Message "Parameter 'RemoveAllNewerThanEnd' specified. Adding ALL files older than start date/time to delete list." $AdditionalFilesNewerThanEnd = $FilesFoundByPattern.where({ $_.LastWriteTime -gt $End }) $FilesToDelete = $FilesToDelete + $AdditionalFilesNewerThanEnd Write-Verbose -Message "Number of files found to be older thand start date/time: $(($AdditionalFilesNewerThanEnd | Measure-Object).Count) in folder $($Folder.FullName)" } } if ($null -ne $FilesToDelete) { Write-Verbose -Message "Deleting files..." $FilesToDelete | Remove-Item -Verbose Write-Verbose -Message "Total number of files deleted in folder $($Folder.FullName) --> $(($FilesToDelete | Measure-Object).Count)" } } } } end { Write-Verbose -Message "DONE" } } #region EndOfScript <# ################################################################################ ################################################################################ # # ______ _ __ _____ _ _ # | ____| | | / _| / ____| (_) | | # | |__ _ __ __| | ___ | |_ | (___ ___ _ __ _ _ __ | |_ # | __| | '_ \ / _` | / _ \| _| \___ \ / __| '__| | '_ \| __| # | |____| | | | (_| | | (_) | | ____) | (__| | | | |_) | |_ # |______|_| |_|\__,_| \___/|_| |_____/ \___|_| |_| .__/ \__| # | | # |_| ################################################################################ ################################################################################ # created with help of http://patorjk.com/software/taag/ #> #endregion |