Skip to content

Commit e6f4272

Browse files
authored
Merge pull request BrentOzarULTD#3951 from BrentOzarULTD/claude/crazy-hodgkin
sp_Blitz: add Azure SQL Database support
2 parents 87ca0f4 + bb49709 commit e6f4272

2 files changed

Lines changed: 156 additions & 41 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ Commonly used parameters:
9393
* @CheckServerInfo = 1 - includes additional rows at priority 250 with server configuration details like service accounts.
9494
* @IgnorePrioritiesAbove = 50 - if you want a daily bulletin of the most important warnings, set @IgnorePrioritiesAbove = 50 to only get the urgent stuff.
9595

96+
**Azure SQL DB support:** sp_Blitz runs on Azure SQL Database (`SERVERPROPERTY('EngineEdition') = 5`) and skips ~40 checks that rely on things Azure SQL DB does not expose: backup history in msdb, SQL Agent jobs and alerts, `xp_*` extended procs (drive space, error log, registry reads), `sys.master_files`, `sp_validatelogins`, cross-database DBCC commands, linked servers, and database mirroring / AGs. When sp_Blitz detects Azure SQL DB, a CheckID 223 "Some Checks Skipped" informational row is returned so you know coverage is reduced. Email output via `@EmailRecipients` (Database Mail is unavailable) and remote output via `@OutputServerName` (no linked servers) are also not supported on Azure SQL DB - sp_Blitz prints a not-supported message and continues instead of erroring. Managed Instance (`EngineEdition = 8`) and Amazon RDS are unaffected and continue to use their existing code paths.
97+
9698
Advanced tips:
9799

98100
* [How to install, run, and centralize the data from sp_Blitz using PowerShell](https://garrybargsley.com/2020/07/14/sp_blitz-for-all-servers/)

sp_Blitz.sql

Lines changed: 154 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ BEGIN
190190
,@TraceFileIssue bit
191191
-- Flag for Windows OS to help with Linux support
192192
,@IsWindowsOperatingSystem BIT
193+
-- Flag for Azure SQL Database (EngineEdition 5) - used to skip incompatible checks and guard email / linked-server output paths
194+
,@IsAzureSQLDB BIT
193195
,@DaysUptime NUMERIC(23,2)
194196
/* For First Responder Kit consistency check:*/
195197
,@spBlitzFullName VARCHAR(1024)
@@ -746,6 +748,9 @@ BEGIN
746748
SELECT @IsWindowsOperatingSystem = 1 ;
747749
END;
748750

751+
-- Flag for Azure SQL Database - used to guard email and linked server output paths
752+
SELECT @IsAzureSQLDB = CASE WHEN CONVERT(INT, SERVERPROPERTY('EngineEdition')) = 5 THEN 1 ELSE 0 END;
753+
749754

750755
IF NOT EXISTS ( SELECT 1
751756
FROM #SkipChecks
@@ -922,6 +927,98 @@ BEGIN
922927
'Managed Instance detected, so we skipped some checks that are not currently possible, relevant, or practical there.' AS Details;
923928
END; /* Azure Managed Instance skipped checks */
924929

930+
/* If the server is Azure SQL Database, skip checks that it doesn't allow */
931+
IF @IsAzureSQLDB = 1
932+
BEGIN
933+
/* Backup / restore history and corruption tracking - msdb does not exist on Azure SQL DB */
934+
INSERT INTO #SkipChecks (CheckID) VALUES (1); /* Full backups */
935+
INSERT INTO #SkipChecks (CheckID) VALUES (2); /* Log backups */
936+
INSERT INTO #SkipChecks (CheckID) VALUES (4); /* Full backup of user DB */
937+
INSERT INTO #SkipChecks (CheckID) VALUES (5); /* Log backup of user DB */
938+
INSERT INTO #SkipChecks (CheckID) VALUES (18); /* Backup to same drive */
939+
INSERT INTO #SkipChecks (CheckID) VALUES (90); /* Database Corruption Detected - reads msdb.dbo.suspect_pages */
940+
INSERT INTO #SkipChecks (CheckID) VALUES (93); /* Backup to same drive as data - joins msdb backup history with sys.master_files */
941+
INSERT INTO #SkipChecks (CheckID) VALUES (177); /* Disabled Internal Monitoring Features - requires dm_server_registry access */
942+
INSERT INTO #SkipChecks (CheckID) VALUES (186); /* MSDB Backup History Purged Too Frequently */
943+
944+
/* SQL Agent - no Agent on Azure SQL DB */
945+
INSERT INTO #SkipChecks (CheckID) VALUES (6); /* Jobs Owned By Users */
946+
INSERT INTO #SkipChecks (CheckID) VALUES (30); /* Alerts not configured */
947+
INSERT INTO #SkipChecks (CheckID) VALUES (31); /* No enabled operators */
948+
INSERT INTO #SkipChecks (CheckID) VALUES (57); /* Agent Job Runs at Startup */
949+
INSERT INTO #SkipChecks (CheckID) VALUES (59); /* Alerts Configured without Follow Up */
950+
INSERT INTO #SkipChecks (CheckID) VALUES (61); /* Agent alerts for severity 19-25 */
951+
INSERT INTO #SkipChecks (CheckID) VALUES (73); /* No Failsafe Operator Configured */
952+
INSERT INTO #SkipChecks (CheckID) VALUES (79); /* Shrink Database Job */
953+
INSERT INTO #SkipChecks (CheckID) VALUES (94); /* Job failure without operator notification */
954+
INSERT INTO #SkipChecks (CheckID) VALUES (96); /* Agent alerts for corruption */
955+
INSERT INTO #SkipChecks (CheckID) VALUES (98); /* Disabled alerts */
956+
INSERT INTO #SkipChecks (CheckID) VALUES (123); /* Agent Jobs Starting Simultaneously */
957+
INSERT INTO #SkipChecks (CheckID) VALUES (180); /* Maintenance plans */
958+
INSERT INTO #SkipChecks (CheckID) VALUES (181); /* Repetitive maintenance tasks */
959+
INSERT INTO #SkipChecks (CheckID) VALUES (219); /* Alerts without event descriptions */
960+
961+
/* Cross-DB / system-DB access not permitted on Azure SQL DB */
962+
INSERT INTO #SkipChecks (CheckID) VALUES (29); /* Tables in model database */
963+
INSERT INTO #SkipChecks (CheckID) VALUES (55); /* Database owner <> sa - queries master.sys */
964+
INSERT INTO #SkipChecks (CheckID) VALUES (68); /* Last good DBCC CHECKDB - DBCC DBINFO cross-DB */
965+
INSERT INTO #SkipChecks (CheckID) VALUES (69); /* High VLF count - DBCC LOGINFO cross-DB */
966+
INSERT INTO #SkipChecks (CheckID) VALUES (71); /* sysadmin in master.sys.syslogins */
967+
INSERT INTO #SkipChecks (CheckID) VALUES (74); /* Trace flags - DBCC TRACESTATUS */
968+
INSERT INTO #SkipChecks (CheckID) VALUES (97); /* Unusual SQL Server Edition */
969+
INSERT INTO #SkipChecks (CheckID) VALUES (2301); /* sp_validatelogins */
970+
971+
/* File layout / tempdb - cannot read tempdb or system DBs cross-DB from a user DB, and sys.master_files is unavailable */
972+
INSERT INTO #SkipChecks (CheckID) VALUES (21); /* Database encrypted - always true on Azure SQL DB */
973+
INSERT INTO #SkipChecks (CheckID) VALUES (24); /* System DB on C drive */
974+
INSERT INTO #SkipChecks (CheckID) VALUES (25); /* TempDB on C Drive - reads sys.master_files */
975+
INSERT INTO #SkipChecks (CheckID) VALUES (26); /* User Databases on C Drive - reads sys.master_files */
976+
INSERT INTO #SkipChecks (CheckID) VALUES (36); /* Slow Storage Reads - joins sys.dm_io_virtual_file_stats with sys.master_files */
977+
INSERT INTO #SkipChecks (CheckID) VALUES (40); /* TempDB only one data file */
978+
INSERT INTO #SkipChecks (CheckID) VALUES (41); /* TempDB file size/growth mismatch */
979+
INSERT INTO #SkipChecks (CheckID, DatabaseName) VALUES (80, 'master'); /* Max file size set */
980+
INSERT INTO #SkipChecks (CheckID, DatabaseName) VALUES (80, 'model'); /* Max file size set */
981+
INSERT INTO #SkipChecks (CheckID, DatabaseName) VALUES (80, 'msdb'); /* Max file size set */
982+
INSERT INTO #SkipChecks (CheckID, DatabaseName) VALUES (80, 'tempdb'); /* Max file size set */
983+
INSERT INTO #SkipChecks (CheckID) VALUES (172); /* TempDB files on C drive */
984+
985+
/* Server / OS / services - not addressable on Azure SQL DB */
986+
INSERT INTO #SkipChecks (CheckID) VALUES (50); /* Max Server Memory - not user-configurable */
987+
INSERT INTO #SkipChecks (CheckID) VALUES (92); /* Drive space - xp_fixeddrives */
988+
INSERT INTO #SkipChecks (CheckID) VALUES (100); /* Remote DAC */
989+
INSERT INTO #SkipChecks (CheckID) VALUES (192); /* IFI - not applicable */
990+
INSERT INTO #SkipChecks (CheckID) VALUES (193); /* xp_readerrorlog for IFI */
991+
INSERT INTO #SkipChecks (CheckID) VALUES (199); /* Default trace */
992+
INSERT INTO #SkipChecks (CheckID) VALUES (211); /* Power plan - xp_regread */
993+
INSERT INTO #SkipChecks (CheckID) VALUES (212); /* Additional instances - xp_regread */
994+
INSERT INTO #SkipChecks (CheckID) VALUES (224); /* SSRS/SSAS/SSIS Installed */
995+
INSERT INTO #SkipChecks (CheckID) VALUES (258); /* SQL Server service running as LocalSystem */
996+
INSERT INTO #SkipChecks (CheckID) VALUES (259); /* Agent service running as LocalSystem */
997+
INSERT INTO #SkipChecks (CheckID) VALUES (260); /* SQL Server service account in Administrators */
998+
INSERT INTO #SkipChecks (CheckID) VALUES (261); /* Agent service account in Administrators */
999+
1000+
/* Replication / mirroring / AGs / clustering - not applicable on Azure SQL DB */
1001+
INSERT INTO #SkipChecks (CheckID) VALUES (53); /* Cluster Node - sys.dm_hadr_* DMVs unavailable */
1002+
INSERT INTO #SkipChecks (CheckID) VALUES (227); /* Database Mirroring */
1003+
INSERT INTO #SkipChecks (CheckID) VALUES (234); /* SQL Server Update May Fail - queries master.sys.master_files */
1004+
INSERT INTO #SkipChecks (CheckID) VALUES (268); /* AG Replica Falling Behind - sys.availability_* DMVs unavailable */
1005+
1006+
INSERT INTO #BlitzResults
1007+
( CheckID ,
1008+
Priority ,
1009+
FindingsGroup ,
1010+
Finding ,
1011+
URL ,
1012+
Details
1013+
)
1014+
SELECT 223 AS CheckID ,
1015+
0 AS Priority ,
1016+
'Informational' AS FindingsGroup ,
1017+
'Some Checks Skipped' AS Finding ,
1018+
'https://learn.microsoft.com/en-us/azure/azure-sql/database/' AS URL ,
1019+
'Azure SQL Database detected, so we skipped some checks that are not currently possible, relevant, or practical there.' AS Details;
1020+
END; /* Azure SQL Database skipped checks */
1021+
9251022
/*
9261023
That's the end of the SkipChecks stuff.
9271024
The next several tables are used by various checks later.
@@ -9844,7 +9941,7 @@ IF NOT EXISTS ( SELECT 1
98449941
DROP TABLE IF EXISTS #MasterFiles;
98459942
CREATE TABLE #MasterFiles (database_id INT, file_id INT, type_desc NVARCHAR(50), name NVARCHAR(255), physical_name NVARCHAR(255), size BIGINT);
98469943
/* Azure SQL Database doesn't have sys.master_files, so we have to build our own. */
9847-
IF ((SERVERPROPERTY('Edition')) = 'SQL Azure'
9944+
IF (@IsAzureSQLDB = 1
98489945
AND (OBJECT_ID('sys.master_files') IS NULL))
98499946
SET @StringToExecute = 'INSERT INTO #MasterFiles (database_id, file_id, type_desc, name, physical_name, size) SELECT DB_ID(), file_id, type_desc, name, physical_name, size FROM sys.database_files;';
98509947
ELSE
@@ -10134,44 +10231,53 @@ IF NOT EXISTS ( SELECT 1
1013410231

1013510232
IF @EmailRecipients IS NOT NULL
1013610233
BEGIN
10137-
10138-
IF @Debug IN (1, 2) RAISERROR('Sending an email.', 0, 1) WITH NOWAIT;
10139-
10140-
/* Database mail won't work off a local temp table. I'm not happy about this hacky workaround either. */
10141-
IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
10142-
SELECT * INTO ##BlitzResults FROM #BlitzResults;
10143-
SET @query_result_separator = char(9);
10144-
SET @StringToExecute = 'SET NOCOUNT ON;SELECT [Priority] , [FindingsGroup] , [Finding] , [DatabaseName] , [URL] , [Details] , CheckID FROM ##BlitzResults ORDER BY Priority , FindingsGroup , Finding , DatabaseName , Details; SET NOCOUNT OFF;';
10145-
SET @EmailSubject = 'sp_Blitz Results for ' + @@SERVERNAME;
10146-
SET @EmailBody = 'sp_Blitz ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)) + '. http://FirstResponderKit.org';
10147-
IF @EmailProfile IS NULL
10148-
EXEC msdb.dbo.sp_send_dbmail
10149-
@recipients = @EmailRecipients,
10150-
@subject = @EmailSubject,
10151-
@body = @EmailBody,
10152-
@query_attachment_filename = 'sp_Blitz-Results.csv',
10153-
@attach_query_result_as_file = 1,
10154-
@query_result_header = 1,
10155-
@query_result_width = 32767,
10156-
@append_query_error = 1,
10157-
@query_result_no_padding = 1,
10158-
@query_result_separator = @query_result_separator,
10159-
@query = @StringToExecute;
10234+
10235+
IF @IsAzureSQLDB = 1
10236+
BEGIN
10237+
IF @Debug IN (1, 2) RAISERROR('Skipping email - Database Mail is not available on Azure SQL Database.', 0, 1) WITH NOWAIT;
10238+
PRINT 'Email output is not supported on Azure SQL Database (Database Mail / msdb.dbo.sp_send_dbmail is unavailable). Skipping email send.';
10239+
END;
1016010240
ELSE
10161-
EXEC msdb.dbo.sp_send_dbmail
10162-
@profile_name = @EmailProfile,
10163-
@recipients = @EmailRecipients,
10164-
@subject = @EmailSubject,
10165-
@body = @EmailBody,
10166-
@query_attachment_filename = 'sp_Blitz-Results.csv',
10167-
@attach_query_result_as_file = 1,
10168-
@query_result_header = 1,
10169-
@query_result_width = 32767,
10170-
@append_query_error = 1,
10171-
@query_result_no_padding = 1,
10172-
@query_result_separator = @query_result_separator,
10173-
@query = @StringToExecute;
10174-
IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
10241+
BEGIN
10242+
10243+
IF @Debug IN (1, 2) RAISERROR('Sending an email.', 0, 1) WITH NOWAIT;
10244+
10245+
/* Database mail won't work off a local temp table. I'm not happy about this hacky workaround either. */
10246+
IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
10247+
SELECT * INTO ##BlitzResults FROM #BlitzResults;
10248+
SET @query_result_separator = char(9);
10249+
SET @StringToExecute = 'SET NOCOUNT ON;SELECT [Priority] , [FindingsGroup] , [Finding] , [DatabaseName] , [URL] , [Details] , CheckID FROM ##BlitzResults ORDER BY Priority , FindingsGroup , Finding , DatabaseName , Details; SET NOCOUNT OFF;';
10250+
SET @EmailSubject = 'sp_Blitz Results for ' + @@SERVERNAME;
10251+
SET @EmailBody = 'sp_Blitz ' + CAST(CONVERT(DATETIME, @VersionDate, 102) AS VARCHAR(100)) + '. http://FirstResponderKit.org';
10252+
IF @EmailProfile IS NULL
10253+
EXEC msdb.dbo.sp_send_dbmail
10254+
@recipients = @EmailRecipients,
10255+
@subject = @EmailSubject,
10256+
@body = @EmailBody,
10257+
@query_attachment_filename = 'sp_Blitz-Results.csv',
10258+
@attach_query_result_as_file = 1,
10259+
@query_result_header = 1,
10260+
@query_result_width = 32767,
10261+
@append_query_error = 1,
10262+
@query_result_no_padding = 1,
10263+
@query_result_separator = @query_result_separator,
10264+
@query = @StringToExecute;
10265+
ELSE
10266+
EXEC msdb.dbo.sp_send_dbmail
10267+
@profile_name = @EmailProfile,
10268+
@recipients = @EmailRecipients,
10269+
@subject = @EmailSubject,
10270+
@body = @EmailBody,
10271+
@query_attachment_filename = 'sp_Blitz-Results.csv',
10272+
@attach_query_result_as_file = 1,
10273+
@query_result_header = 1,
10274+
@query_result_width = 32767,
10275+
@append_query_error = 1,
10276+
@query_result_no_padding = 1,
10277+
@query_result_separator = @query_result_separator,
10278+
@query = @StringToExecute;
10279+
IF (OBJECT_ID('tempdb..##BlitzResults', 'U') IS NOT NULL) DROP TABLE ##BlitzResults;
10280+
END;
1017510281
END;
1017610282

1017710283
/* Checks if @OutputServerName is populated with a valid linked server, and that the database name specified is valid */
@@ -10180,11 +10286,18 @@ IF NOT EXISTS ( SELECT 1
1018010286
DECLARE @LinkedServerDBCheck NVARCHAR(2000);
1018110287
DECLARE @ValidLinkedServerDB INT;
1018210288
DECLARE @tmpdbchk table (cnt int);
10183-
IF @OutputServerName IS NOT NULL
10289+
IF @OutputServerName IS NOT NULL AND @IsAzureSQLDB = 1
1018410290
BEGIN
10185-
10291+
IF @Debug IN (1, 2) RAISERROR('Skipping linked server output - not supported on Azure SQL Database.', 0, 1) WITH NOWAIT;
10292+
PRINT 'Linked server output (@OutputServerName) is not supported on Azure SQL Database. Skipping remote output.';
10293+
SET @ValidOutputServer = 0;
10294+
SET @ValidOutputLocation = 0;
10295+
END;
10296+
ELSE IF @OutputServerName IS NOT NULL
10297+
BEGIN
10298+
1018610299
IF @Debug IN (1, 2) RAISERROR('Outputting to a remote server.', 0, 1) WITH NOWAIT;
10187-
10300+
1018810301
IF EXISTS (SELECT server_id FROM sys.servers WHERE QUOTENAME([name]) = @OutputServerName)
1018910302
BEGIN
1019010303
SET @LinkedServerDBCheck = 'SELECT 1 WHERE EXISTS (SELECT * FROM '+@OutputServerName+'.master.sys.databases WHERE QUOTENAME([name]) = '''+@OutputDatabaseName+''')';

0 commit comments

Comments
 (0)