Flexibel deletion of files by age
Maintaining free disk space on a shared desktop or any other non-persistent environment can pollute the systems in the background over time. The below script can be used to clean out obsolete files which are older than a specified number of days.
The main script requires two mandatory parameters, folder path and the number of days. Optional parameters are the file mask and the choice to clean out recursively. By default all files are cleaned within the specified folder only. The main scripts is being triggered by a launcher script where you can define which and how folders should be processed.
The launcher script
The following sections shows an example of how the launcher script could look like.
invoke-expression -Command "Path\DelFilesByAge.ps1 -foldername 'C:\windows\Logs\CBS' -numdays 14 -SubFolderSwitch sub -FileMask *.cab" invoke-expression -Command "Path\DelFilesByAge.ps1 -foldername 'C:\windows\Logs\CBS' -numdays 14 -SubFolderSwitch sub -FileMask *.log" invoke-expression -Command "Path\DelFilesByAge.ps1 -foldername 'C:\Windows\Temp' -numdays 14 -SubFolderSwitch sub -FileMask cab*.*" invoke-expression -Command "Path\DelFilesByAge.ps1 -foldername 'C:\Windows\Temp' -numdays 14"
Main DelFilesByAge script
Below you find the code for the main script. You may call it ‘DelFilesByAge.ps1’, and refer to it by calling it from another script for which I placed an example above. The launcher script can be triggered by a scheduled task, or during a regular maintenance cycle.
# .SYNOPSIS This script will delete files from a folder (and optionally from all subfolders as well) older than a specified number of days. .DESCRIPTION . .PARAMETER FolderName Folder from which files are to be delete .PARAMETER NumDays Number of days. Files this many days old or older will be deleted .PARAMETER SubFolderSwitch provide 'SUB' to delete files from folder and all subfolders .PARAMETER FileMask File Mask (default is *.*) .EXAMPLE C:\PPG\CMD\DelFilesByAge.ps1 -foldername 'C:\windows\Logs\CBS' -numdays 14 -SubFolderSwitch sub -FileMask *.cab .NOTES Author: S.feenstra@loginconsultants.nl Date: February, 2017 Version: 1.0 - Initial version Version: 1.1 - Added Removal of empty folders under 'Foldername' using tail recursive seach, And filesize count for the to be processed items #> [CmdletBinding()] Param ( [Parameter(Mandatory=$True,Position=0,HelpMessage="Folder from which files are to be delete")] [string]$FolderName, [Parameter(Mandatory=$True,Position=1,HelpMessage="Number of days. Files this many days old or older will be deleted")] [int]$NumDays, [Parameter(Position=2,HelpMessage="provide 'SUB' to delete files from folder and all subfolders")] [string]$SubFolderSwitch = "NSF", [Parameter(Position=3,HelpMessage="File Mask (default is *.*)")] [string]$FileMask = "*.*" ) #Set some additional Variables $WhatIfPreference = $false $LogFolder = "${env:RES-LOGLOCATION}\RES\Maintenance\" $Now = Get-Date $LastWrite = $Now.AddDays(-$NumDays) $Files = $null;$EmptyFolders = $null # Function to tail recurse foldertree, to be able to remove empty folder bottom up. $TailRecursion = { param( $Path ) foreach ($childDirectory in Get-ChildItem -Force -LiteralPath $Path -Directory -ea 0) { & $tailRecursion -Path $childDirectory.FullName } $currentChildren = Get-ChildItem -Force -LiteralPath $Path -ea 0 $isEmpty = $currentChildren -eq $null if ($isEmpty) { try {Remove-Item -Force -LiteralPath $Path -ea Stop logaction "Empty folder at [$($Path)] has been removed" }Catch [Exception] {Logaction "Remove-Item - $_"} } } # Create Logfolder when it does not exist if (!(test-path $LogFolder)){try{New-Item -ItemType directory -Path $LogFolder -Force}catch [Exception]{Write-warning $_.Exception.Message}} [string]$LogFile = "_DelFilesDirList.txt" [string]$LogFileDate = get-date -format "dd-MM-yyyy" [string]$LogFileName = $LogFolder + $LogFileDate + $LogFile Function LogAction { Param([string]$i) [string]$LogDate = $(get-date -uformat "%d-%m-%Y | %H:%M:%S.%ms") + " |" Add-Content -path $LogFileName -value "$LogDate $i" } if ((test-path $logfilename) -ne $true){LogAction "Initializing new delete files by age log"} Logaction "/// Start Cleaning files in folder [$foldername]$(@{"SUB" = " and subfolders";"NSF" = $null}[$SubFolderSwitch.ToUpper()]) older than [$NumDays] days with filemask [$FileMask]" # First Check if Foldername exists if ((test-path $FolderName) -eq $true){ #----- get files based on lastwrite filter and specified folder ---# if ($SubFolderSwitch.ToUpper() -eq "NSF") { try {$Files = Get-Childitem $FolderName -File -Filter $FileMask -ea stop | Where {$_.LastWriteTime -le "$LastWrite"} } Catch [Exception] {Logaction "Get-Childitem - $_" } } if ($SubFolderSwitch.ToUpper() -eq "SUB") { try {$Files = Get-Childitem $FolderName -File -Filter $FileMask -Recurse -ea stop | Where {$_.LastWriteTime -le "$LastWrite"} } Catch [Exception] {Logaction "Get-Childitem - $_"} } # Measure the size of to be processed files in Megabytes $FilesSize = "{0:N2}" -f (($Files | Measure-Object -property length -sum).sum / 1MB);if ($filesize = $null){$filesize = 0} # Log the to be processed items logaction "Processing [$($files.count)] files and [$FilesSize] MB in [$FolderName]$(@{"SUB" = " and subfolders";"NSF" = $null}[$SubFolderSwitch.ToUpper()])" # Process the files foreach ($File in $Files) { if ($File -ne $null) { try {Remove-Item $File.FullName -Verbose -ea stop logaction "File [$($File.FullName)] with last write time [$($file.LastWriteTime)] has been removed" }Catch [Exception] {Logaction "Remove-Item - $_"} } else { Logaction "No more files to delete!" } } # Process EmptyFolders & $TailRecursion -Path $Foldername # Finish logaction "Processing [$FolderName] Done" }Else{logaction "Folder [$FolderName] Does not exist"}
Syntax
DelFilesByAge.sp1 [-Foldername] <String> [-NumDays] <Int32> [[-SubFolderSwitch] <String> [[-FileMask] <String>
Thanks, great article.
Thanks for another fantastic post. The place else may just anybody get that type of info in such a perfect method of writing? I have a presentation subsequent week, and I’m on the search for such info.