Querying Maintenance Plans
Lots of DBA’s use the built in maintenance plans to set up backups and other database maintenance. SQL Server, through SSMS provides the user with a drag and drop experience to create some pretty intelligent backup and maintenance plans. There plans are nothing more than SSIS packages stored in MSDB on the instance they are created.
One problem I found in working with maintenance plans is the ability to query configuration values that have been set up, such as the backup location. In working with a client recently we had to move backups from one location to another and we had no real way to find out where the current backups were pointing.
With the help of my fellow co-workers Jason Strate (blog|twitter) and Brad Ball (blog|twitter) I was able to get started finding out how to query this backup information. There is a table called sysssispackages (2008+) and sysdtspackages90 (2005) that are located in the MSDB database that contain the binary version of the packages. We were able to convert that to XML, then use XQuery to find out the backup information I needed. I also created the script so it would work for 2005 as well as 2008 and 2012. Please enjoy and I hope you find this as useful as I did
--2005
IF SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0,CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0)) = 9
BEGIN
WITH XMLNAMESPACES ('www.microsoft.com/SqlServer/Dts' AS DTS
, 'www.microsoft.com/sqlserver/dts/tasks/sqltask' AS SQLTask)
,ssis AS (
SELECT name
, CAST(CAST(packagedata AS varbinary(MAX)) AS XML) AS package
FROM [msdb].[dbo].[sysdtspackages90]
WHERE packagetype = 6 --This is "Maintenance Plan" Category
)
SELECT s.name as MaintenancePlanName,
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupAction)[1]', 'INT')
WHEN 0 THEN
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupIsIncremental)[1]', 'bit')
WHEN 1 THEN 'DIFFERENTIAL'
WHEN 0 THEN 'FULL'
ELSE 'UNKNOWN'
END
WHEN 1 THEN 'FILES'
WHEN 2 THEN 'LOG'
ELSE 'UNKNOWN'
END as BackupType,
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupCompressionAction)[1]', 'int')
WHEN 0 THEN 'SERVER DEFAULT CONFIG'
WHEN 1 THEN 'YES'
WHEN 2 THEN 'NO'
END as Compressed,
c.value('(SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath)[1]', 'VARCHAR(MAX)') as BackupLocation
FROM ssis s
CROSS APPLY package.nodes('//DTS:ObjectData') t(c)
WHERE c.exist('SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath') = 1
END
--2008 and above
ELSE IF SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0,CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0)) >= 10
BEGIN
WITH XMLNAMESPACES ('www.microsoft.com/SqlServer/Dts' AS DTS
, 'www.microsoft.com/sqlserver/dts/tasks/sqltask' AS SQLTask)
,ssis AS (
SELECT name
, CAST(CAST(packagedata AS varbinary(MAX)) AS XML) AS package
FROM [msdb].[dbo].[sysssispackages]
WHERE packagetype = 6 --This is "Maintenance Plan" Category
)
SELECT s.name as MaintenancePlanName,
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupAction)[1]', 'INT')
WHEN 0 THEN
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupIsIncremental)[1]', 'bit')
WHEN 1 THEN 'DIFFERENTIAL'
WHEN 0 THEN 'FULL'
ELSE 'UNKNOWN'
END
WHEN 1 THEN 'FILES'
WHEN 2 THEN 'LOG'
ELSE 'UNKNOWN'
END as BackupType,
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupCompressionAction)[1]', 'int')
WHEN 0 THEN 'SERVER DEFAULT CONFIG'
WHEN 1 THEN 'YES'
WHEN 2 THEN 'NO'
END as Compressed,
c.value('(SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath)[1]', 'VARCHAR(MAX)') as BackupLocation
FROM ssis s
CROSS APPLY package.nodes('//DTS:ObjectData') t(c)
WHERE c.exist('SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath') = 1
END
Hi,
Its a good script, I need to know is it possible to create a Maintenance plan by a script with all the tasks like backup,Index maintenance,shrink db etc in SQL server.
If yes, could you please send me the script please.
Regards,
Dilip
This looks like a great report but it does not show the database names that are being backed up by the plan. Could this be added?
Would be nice if….
Copy the code ends up in a mess. Post the code so that is retrievable than I can test it.
A very useful script. Thanks for documenting your efforts.