The cleanup task simply runs an extended stored procedure called xp_delete_file against a list of files. This procedure checks the supplied file to validate that it is either a SQL Server backup file or a SQL Server log file. If it is, and it is older than the supplied date, the file is deleted.
For a custom solution like yours, you should use PowerShell to extract a list of backup files that meet your requirements and them remove them using Remove-Item. Something like below should work.
It queries the backup history tables in msdb then uses the returned list of backups to feed into a loop. The loop tests if the file exists and if so it removes the file.
$SQLScript = "DECLARE @DaysToKeep INT = 7,
@LogDaysToKeep INT = 3
;WITH FullBackup AS (
SELECT bs.database_name,
bs.backup_start_date,
bmf.physical_device_name,
bs.backup_set_id,
bs.compressed_backup_size,
bs.first_lsn,
'Full' AS [Type]
FROM msdb..backupset bs WITH (NOLOCK)
INNER JOIN msdb..backupmediafamily bmf WITH (NOLOCK) ON bmf.media_set_id = bs.media_set_id
WHERE bs.[type] = 'D'
AND bs.backup_start_date < DATEADD(DAY, -@DaysToKeep, GETDATE())
), DiffBackup AS (
SELECT bs.database_name,
bs.backup_start_date,
bmf.physical_device_name,
bs.backup_set_id,
bs.compressed_backup_size,
'Diff' AS [Type]
FROM msdb..backupset bs WITH (NOLOCK)
INNER JOIN msdb..backupmediafamily bmf WITH (NOLOCK) ON bmf.media_set_id = bs.media_set_id
LEFT JOIN FullBackup fb ON fb.database_name = bs.database_name AND bs.database_name = fb.database_name AND bs.database_backup_lsn = fb.first_lsn
WHERE bs.[type] = 'I'
AND bs.backup_start_date >= fb.backup_start_date
), LogBackups AS (
SELECT bs.database_name,
bs.backup_start_date,
bmf.physical_device_name,
bs.backup_set_id,
bs.compressed_backup_size,
'Log' AS [Type]
FROM msdb..backupset bs WITH (NOLOCK)
INNER JOIN msdb..backupmediafamily bmf WITH (NOLOCK) ON bmf.media_set_id = bs.media_set_id
LEFT JOIN FullBackup fb ON fb.database_name = bs.database_name AND bs.database_name = fb.database_name AND bs.database_backup_lsn = fb.first_lsn
LEFT JOIN DiffBackup dd ON dd.database_name = bs.database_name
WHERE bs.[type] = 'L'
AND bs.backup_start_date >= fb.backup_start_date
AND bs.backup_start_date <= DATEADD(DAY, -@LogDaysToKeep, GETDATE())
), Backups AS (
SELECT database_name,
physical_device_name,
[type],
compressed_backup_size,
backup_start_date
FROM FullBackup
UNION
SELECT database_name,
physical_device_name,
[type],
compressed_backup_size,
backup_start_date
FROM DiffBackup
UNION
SELECT database_name,
physical_device_name,
[type],
compressed_backup_size,
backup_start_date
FROM LogBackups
)
SELECT b.database_name,
b.[type],
b.backup_start_date,
b.physical_device_name
FROM Backups b"
$BackupFiles = Invoke-Sqlcmd -ServerInstance localhost -Database msdb -Query $SQLScript
foreach ($File in $BackupFiles)
{
if (Test-Path $File.physical_device_name)
{
Write-Output "Remove file $($File.physical_device_name)..."
Remove-Item -Path $File.physical_device_name
}
else
{
Write-Output "File $($File.physical_device_name) no longer exists. Skipping."
}
}
Save this as a script file on the SQL Server and call it via a SQL Server Agent job to automate the cleanup as per your requirements.