|
4 | 4 | .DESCRIPTION |
5 | 5 | Removes backup files older than a specified retention period for all databases of an instance. |
6 | 6 | Only deletes files matching the specified backup type extension (.bak for Full/Diff, .trn for Log). |
7 | | - Supports exclusion of databases by exact name or SQL LIKE patterns (e.g. %_NOBACKUP, TEST%). |
| 7 | + Supports inclusion and exclusion of databases by exact name or SQL LIKE patterns (e.g. %_NOBACKUP, TEST%). |
8 | 8 | |
9 | 9 | .PARAMETER SqlInstance |
10 | 10 | The SQL Server instance whose backup files should be purged. |
|
23 | 23 | .PARAMETER RetentionHours |
24 | 24 | Retention period in hours. Files older than this will be deleted. |
25 | 25 |
|
| 26 | + .PARAMETER IncludeDatabases |
| 27 | + Array of database names or SQL LIKE patterns to include in purge. |
| 28 | + If specified, ONLY databases matching these patterns will be purged. |
| 29 | + Exact names (e.g. "MyDB") and patterns using % and _ wildcards are supported. |
| 30 | + Example: @("PROD%", "MyDB", "%_CRITICAL") |
| 31 | +
|
26 | 32 | .PARAMETER ExcludeDatabases |
27 | 33 | Array of database names or SQL LIKE patterns to exclude from purge. |
28 | 34 | Exact names (e.g. "MyDB") and patterns using % and _ wildcards are supported. |
|
66 | 72 | [Parameter(Mandatory)] [ValidateSet('Full','Diff','Log','All')] [string] $BackupType, |
67 | 73 | [Parameter(Mandatory)] [string] $BackupDirectory, |
68 | 74 | [Parameter(Mandatory)] [Int32] $RetentionHours, |
| 75 | + [Parameter()] [string[]] $IncludeDatabases = @(), |
69 | 76 | [Parameter()] [string[]] $ExcludeDatabases = @(), |
70 | 77 | [Parameter()] [switch] $WhatIf, |
71 | 78 | [Parameter()] [string] $LogLevel = "INFO", |
|
83 | 90 | return "^${escaped}$" |
84 | 91 | } |
85 | 92 |
|
86 | | - function Test-DatabaseExcluded { |
| 93 | + function Test-DatabaseMatchesPattern { |
87 | 94 | param( |
88 | 95 | [string]$DatabaseName, |
89 | | - [string[]]$ExcludePatterns |
| 96 | + [string[]]$Patterns |
90 | 97 | ) |
91 | | - foreach ($pattern in $ExcludePatterns) { |
| 98 | + foreach ($pattern in $Patterns) { |
92 | 99 | if ($pattern -match '[%_]') { |
93 | 100 | $regex = Convert-SqlLikeToRegex -Pattern $pattern |
94 | 101 | if ($DatabaseName -match $regex) { return $true } |
|
127 | 134 | Write-Log -Level INFO -Message "Parameter BackupType : ${BackupType}" |
128 | 135 | Write-Log -Level INFO -Message "Parameter BackupDirectory : ${BackupDirectory}" |
129 | 136 | Write-Log -Level INFO -Message "Parameter RetentionHours : ${RetentionHours}" |
| 137 | + Write-Log -Level INFO -Message "Parameter IncludeDatabases : $($IncludeDatabases -join ', ')" |
130 | 138 | Write-Log -Level INFO -Message "Parameter ExcludeDatabases : $($ExcludeDatabases -join ', ')" |
131 | 139 |
|
132 | 140 | # Determine which extensions and subfolder patterns to target |
|
180 | 188 | foreach ($group in $groupedFiles) { |
181 | 189 | $dbName = $group.Name |
182 | 190 |
|
| 191 | + # Check inclusion filter |
| 192 | + if ($IncludeDatabases.Count -gt 0 -and -not (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $IncludeDatabases)) { |
| 193 | + $skippedSizeMB = [math]::Round(($group.Group | Measure-Object -Property Length -Sum).Sum / 1MB, 2) |
| 194 | + Write-Log -Level INFO -Message "SKIPPED (not included): ${dbName} - $($group.Count) file(s), ${skippedSizeMB} MB" |
| 195 | + $totalSkippedCount += $group.Count |
| 196 | + continue |
| 197 | + } |
| 198 | + |
183 | 199 | # Check exclusion |
184 | | - if ($ExcludeDatabases.Count -gt 0 -and (Test-DatabaseExcluded -DatabaseName $dbName -ExcludePatterns $ExcludeDatabases)) { |
| 200 | + if ($ExcludeDatabases.Count -gt 0 -and (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $ExcludeDatabases)) { |
185 | 201 | $skippedSizeMB = [math]::Round(($group.Group | Measure-Object -Property Length -Sum).Sum / 1MB, 2) |
186 | 202 | Write-Log -Level INFO -Message "SKIPPED (excluded): ${dbName} - $($group.Count) file(s), ${skippedSizeMB} MB" |
187 | 203 | $totalSkippedCount += $group.Count |
|
217 | 233 | $wouldDeleteCount = ($allFiles | Where-Object { |
218 | 234 | $parts = $_.FullName.Replace($BackupDirectory, '').TrimStart('\').Split('\') |
219 | 235 | $dbName = if ($parts.Count -ge 3) { $parts[2] } else { "UNKNOWN" } |
220 | | - -not (Test-DatabaseExcluded -DatabaseName $dbName -ExcludePatterns $ExcludeDatabases) |
| 236 | + $included = ($IncludeDatabases.Count -eq 0) -or (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $IncludeDatabases) |
| 237 | + $excluded = ($ExcludeDatabases.Count -gt 0) -and (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $ExcludeDatabases) |
| 238 | + $included -and -not $excluded |
221 | 239 | }).Count |
222 | 240 | $wouldDeleteSizeMB = [math]::Round(($allFiles | Where-Object { |
223 | 241 | $parts = $_.FullName.Replace($BackupDirectory, '').TrimStart('\').Split('\') |
224 | 242 | $dbName = if ($parts.Count -ge 3) { $parts[2] } else { "UNKNOWN" } |
225 | | - -not (Test-DatabaseExcluded -DatabaseName $dbName -ExcludePatterns $ExcludeDatabases) |
| 243 | + $included = ($IncludeDatabases.Count -eq 0) -or (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $IncludeDatabases) |
| 244 | + $excluded = ($ExcludeDatabases.Count -gt 0) -and (Test-DatabaseMatchesPattern -DatabaseName $dbName -Patterns $ExcludeDatabases) |
| 245 | + $included -and -not $excluded |
226 | 246 | } | Measure-Object -Property Length -Sum).Sum / 1MB, 2) |
227 | 247 | Write-Host "" |
228 | 248 | Write-Host "=== WhatIf Summary ===" -ForegroundColor Cyan |
|
0 commit comments