Private/Remove-DailyBackup.ps1
function Remove-DailyBackup { <# .SYNOPSIS Removes old daily backup directories while keeping a specified number of recent backups. .DESCRIPTION Cleans up old daily backup directories by deleting the oldest backup folders first, while preserving a specified minimum number of recent backups. Only directories with date-formatted names (yyyy-MM-dd pattern) are considered for deletion. The function supports ShouldProcess for safe testing and will skip deletion if the number of existing backups doesn't exceed the retention limit. .PARAMETER Path The root directory path where daily backup folders are stored. This should be the parent directory containing date-named subdirectories (e.g., '2025-08-24'). .PARAMETER BackupsToKeep The minimum number of backup directories to retain. Older backups beyond this number will be deleted. Must be a positive integer. .PARAMETER VerboseEnabled Controls whether verbose output is displayed during the cleanup operation. When $true, detailed information about the deletion process is shown. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. This function does not return any objects. .NOTES - Only directories matching the yyyy-MM-dd date pattern are processed - Backups are sorted by date (parsed from folder name) before deletion - Uses SupportsShouldProcess for WhatIf and Confirm support - Continues operation even if individual directory deletions fail - Skips cleanup if total backups don't exceed the retention limit .EXAMPLE PS > Remove-DailyBackup -Path 'C:\Backups' -BackupsToKeep 7 -VerboseEnabled $true Keeps the 7 most recent daily backup folders, removes older ones .EXAMPLE PS > Remove-DailyBackup -Path '/home/user/backups' -BackupsToKeep 3 -WhatIf Shows which backup directories would be deleted without actually removing them .EXAMPLE PS > Remove-DailyBackup -Path 'C:\DailyBackups' -BackupsToKeep 14 Maintains a 2-week retention policy (14 days) for backup directories #> [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [int] $BackupsToKeep, [Parameter(Mandatory = $false)] [bool] $VerboseEnabled = $false ) $qualifiedBackupDirs = @(Get-ChildItem -LiteralPath $Path -Directory -ErrorAction 'SilentlyContinue' | Where-Object { $_.Name -match '^\d{4}-\d{2}-\d{2}$' }) if ($qualifiedBackupDirs.Length -eq 0) { Write-Verbose ('New-DailyBackup:Remove-DailyBackup> No qualified backup directories to delete were detected in: {0}' -f $Path) -Verbose:$VerboseEnabled return } # Create a hashtable so we can sort backup directories based on their date-formatted folder name ('yyyy-MM-dd') $backups = @{ } foreach ($backupDir in $qualifiedBackupDirs) { $backups.Add($backupDir.FullName, [System.DateTime]$backupDir.Name) } $sortedBackupPaths = ($backups.GetEnumerator() | Sort-Object -Property Value | ForEach-Object { $_.Key }) if ($sortedBackupPaths.Count -gt $BackupsToKeep) { for ($i = 0; $i -lt ($sortedBackupPaths.Count - $BackupsToKeep); $i++) { $backupPath = $sortedBackupPaths[$i] if ($PSCmdlet.ShouldProcess($backupPath, 'Remove backup directory')) { Write-Verbose ('New-DailyBackup:Remove-DailyBackup> Removing old backup directory: {0}' -f $backupPath) -Verbose:$VerboseEnabled Remove-ItemAlternative -LiteralPath $backupPath -WhatIf:$WhatIfPreference -Verbose:$VerboseEnabled Write-Verbose ('New-DailyBackup:Remove-DailyBackup> Successfully removed: {0}' -f $backupPath) -Verbose:$VerboseEnabled } } } else { Write-Verbose 'New-DailyBackup:Remove-DailyBackup> No surplus daily backups to delete' -Verbose:$VerboseEnabled } } |