Flexibel deletion of files by age

Reading Time: 3 minutes




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>

Updates

[03/15/2017] – Added Removal of empty folders under ‘Foldername’ using tail recursive seach, And filesize count for the to be processed items

2 Comments

Add a Comment

Your email address will not be published. Required fields are marked *