@@ -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