USE [HCITools] GO IF EXISTS (SELECT * FROM sys.objects o JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE o.name = 'sp_ddl_alerts' AND OBJECTPROPERTY(object_id,N'IsProcedure') = 1 AND s.name = 'dba') DROP PROCEDURE [dba].[sp_ddl_alerts] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dba].[sp_ddl_alerts] AS /*============================================================================= Explication du traitement realise par la SP ------------------------------------------- Cette SP est exécutée toute les jours et check les modifications sur les paramètres des bases. Les résultats sont envoyés par mail Parametres ---------- Creation : 22.08.2019 / SPE Modifications : 06.09.19 / SPE : SQL 2014 compatibility modifications 27.09.19 / SPE : Temporary remove trustworth check 09.02.21 / SPE : #TFS62610# - Update all mail configurations to avoid SPAM 17.03.22 - FLA : Change DBA mail 17.08.23 / SPE : OCTPDBA-726: Replace mail profile name APSSQL_MAIL_PROFILE into AzureManagedInstance_dbmail_profile to be SQL managed instances compatible =============================================================================*/ SET NOCOUNT ON; /*------------------- Declaration des variables --------------------*/ DECLARE @errno int, @cvCurrentOrganizationalUnit int, @subsidiary_id int, @totAlerts int, @totDDL int, @html nvarchar(max), @errmsg varchar(255), @email varchar(255), @subject varchar(255), @out_default_value varchar(60), @format varchar(60), @mailImportance varchar(6), @ou varchar(3) /*-------------------------- Traitement ---------------------------*/ BEGIN TRY /* ------------------------------------------------------------------------------------------------------------------------------------- */ /* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 1 : RETRIEVE FORMAT AND OU CODE /////////////////////////////////////////////////// */ /* ------------------------------------------------------------------------------------------------------------------------------------- */ IF EXISTS(SELECT 1 FROM [master].[cfg].[InstanceContext] WHERE Business = 'TPPHAR') BEGIN /* Get the cvCurrentOrganizationalUnit */ EXEC arizona.dbo.sp_bmc_Bmc_Applic_Default @in_job_type = 3, @in_param_int_1 = null, @in_param_int_2 = null, @in_param_varchar_1 = 'cvCurrentOrganizationalUnit', @out_default_value = @out_default_value OUTPUT, @out_param_int_1 = null; SELECT @cvCurrentOrganizationalUnit = convert(int,@out_default_value); /* Check if we have a value, if not leave this SP */ IF @cvCurrentOrganizationalUnit is null BEGIN SELECT @errno = 70001, @errmsg = '(APS) Error cvCurrentOrganizationalUnit does not exist!'; goto error_99; END /* Get the subsidiary id and OU code */ SELECT @subsidiary_id = ou.OU_subsidiary, @ou = ou.OU_Code FROM arizona.dbo.Organizational_unit ou with (nolock) WHERE ou.Organizational_unit_ID = @cvCurrentOrganizationalUnit; /* Check if we have a value, if not leave this SP */ IF @subsidiary_id is null BEGIN SELECT @errno = 70001, @errmsg = '(APS) Error subsidiary_id does not exist!'; goto error_99; END /* Get the current format */ SELECT @format = sub.SUB_code FROM arizona.dbo.Subsidiary sub with (nolock) WHERE sub.Subsidiary_ID = @subsidiary_id; /* Check if we have a value, if not leave this SP */ IF @format is null BEGIN SELECT @errno = 70001, @errmsg = '(APS) Error format does not exist!'; goto error_99; END /* Change the value into a compatible format */ IF @format = 'COOP' BEGIN SET @format = 'CVI' END IF @format = 'CENT' BEGIN SET @format = 'SUN' END IF @format = '000' BEGIN SET @format = 'AAI' END END ELSE BEGIN SELECT @format = DnsAlias FROM [master].[cfg].[Identity] SET @ou = '' END /* ------------------------------------------------------------------------------------------------------------------------------------- */ /* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 2 : RETRIEVE DDL EVENTS /////////////////////////////////////////////////// */ /* ------------------------------------------------------------------------------------------------------------------------------------- */ /* Temp table #AlterRules with alerts template */ CREATE TABLE #AlterRules(AlertRule varchar(100)) /* Template with all DO NOT settings */ INSERT INTO #AlterRules(AlertRule) VALUES ('AUTO_CLOSE ON'),('AUTO_CREATE_STATISTICS OFF'),('AUTO_SHRINK ON'),('ALLOW_SNAPSHOT_ISOLATION ON'),('ANSI_NULL_DEFAULT OFF'),('ANSI_NULL OFF'),('ANSI_PADDING ON'), ('ANSI_WARNINGS ON'),('ARITHABORT OFF'),('CONCAT_NULL_YIELDS_NULL OFF'),('DB_CHAINING ON'),('DATE_CORRELATION_OPTIMIZATION ON'),('READ_COMMITTED_SNAPSHOT ON'),('NUMERIC_ROUNDABORT OFF'), ('PARAMETERIZATION FORCED'),('QUOTED_IDENTIFIER OFF'),('RECURSIVE_TRIGGERS ON'),('TRUSTWORTHY ON'),('PAGE_VERIFY NONE'),('PAGE_VERIFY TORN_PAGE_DETECTION'),('ENCRYPTION ON') /* Insert into #DDLAlertLog temp table all DDL events of type alter database for the last 24 hours */ SELECT DA_App_Name, DA_Host_Name, DA_Event_Xml.value('(./EVENT_INSTANCE/PostTime)[1]','NVARCHAR(MAX)') AS PostTime, DA_Event_Xml.value('(./EVENT_INSTANCE/SPID)[1]','NVARCHAR(MAX)') AS SPID, DA_Event_Xml.value('(./EVENT_INSTANCE/ServerName)[1]','NVARCHAR(MAX)') AS ServerName, DA_Event_Xml.value('(./EVENT_INSTANCE/LoginName)[1]','NVARCHAR(MAX)') AS LoginName, DA_Event_Xml.value('(./EVENT_INSTANCE/UserName)[1]','NVARCHAR(MAX)') AS UserName, DA_Event_Xml.value('(./EVENT_INSTANCE/DatabaseName)[1]','NVARCHAR(MAX)') AS DatabaseName, DA_Event_Xml.value('(./EVENT_INSTANCE/SchemaName)[1]','NVARCHAR(MAX)') AS SchemaName, DA_Event_Xml.value('(./EVENT_INSTANCE/ObjectName)[1]','NVARCHAR(MAX)') AS ObjectName, DA_Event_Xml.value('(./EVENT_INSTANCE/ObjectType)[1]','NVARCHAR(MAX)') AS ObjectType, DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)') AS CommandText, REPLACE(REPLACE(REPLACE(SUBSTRING(LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(REPLACE(DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)'), CHAR(10), CHAR(32)),CHAR(13), CHAR(32)),CHAR(160), CHAR(32)),CHAR(9),CHAR(32)))), CHARINDEX('SET', REPLACE(DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)'),' ','')) + 6, LEN(REPLACE(DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)'),' ',''))),'WITHNO_WAIT',''),'WITHROLLBACKIMMEDIATE',''),' ','') AS CommandAction INTO #DDLAlertLog FROM [master].[dba].[DDL_audit] WHERE DA_Event_Xml.value('(./EVENT_INSTANCE/EventType)[1]','NVARCHAR(MAX)') = 'ALTER_DATABASE' AND DA_Event_Xml.value('(./EVENT_INSTANCE/PostTime)[1]','NVARCHAR(MAX)') > GETDATE()-1 AND DA_App_Name <> '.Net SqlClient Data Provider' AND DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)') not like '%TRUSTWORTHY%' UNION ALL SELECT DA_App_Name, DA_Host_Name, DA_Event_Xml.value('(./EVENT_INSTANCE/PostTime)[1]','NVARCHAR(MAX)') AS PostTime, DA_Event_Xml.value('(./EVENT_INSTANCE/SPID)[1]','NVARCHAR(MAX)') AS SPID, DA_Event_Xml.value('(./EVENT_INSTANCE/ServerName)[1]','NVARCHAR(MAX)') AS ServerName, DA_Event_Xml.value('(./EVENT_INSTANCE/LoginName)[1]','NVARCHAR(MAX)') AS LoginName, DA_Event_Xml.value('(./EVENT_INSTANCE/UserName)[1]','NVARCHAR(MAX)') AS UserName, DA_Event_Xml.value('(./EVENT_INSTANCE/DatabaseName)[1]','NVARCHAR(MAX)') AS DatabaseName, DA_Event_Xml.value('(./EVENT_INSTANCE/SchemaName)[1]','NVARCHAR(MAX)') AS SchemaName, DA_Event_Xml.value('(./EVENT_INSTANCE/ObjectName)[1]','NVARCHAR(MAX)') AS ObjectName, DA_Event_Xml.value('(./EVENT_INSTANCE/ObjectType)[1]','NVARCHAR(MAX)') AS ObjectType, DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)') AS CommandText, '' AS CommandAction FROM [master].[dba].[DDL_audit] WHERE DA_Event_Xml.value('(./EVENT_INSTANCE/EventType)[1]','NVARCHAR(MAX)') = 'ALTER_AUTHORIZATION_DATABASE' AND replace(DA_Event_Xml.value('(./EVENT_INSTANCE/TSQLCommand/CommandText)[1]','NVARCHAR(MAX)'),'[','!') not like '%!sa%' AND DA_Event_Xml.value('(./EVENT_INSTANCE/PostTime)[1]','NVARCHAR(MAX)') > GETDATE()-1 AND DA_App_Name <> '.Net SqlClient Data Provider' ORDER BY DA_App_Name DESC /* ------------------------------------------------------------------------------------------------------------------------------------- */ /* \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 3 : CREATE AND SEND MAIL /////////////////////////////////////////////////// */ /* ------------------------------------------------------------------------------------------------------------------------------------- */ /* Count total critical alerts and set mail level */ SELECT @totDDL = COUNT(*) FROM #DDLAlertLog AL SELECT @totAlerts = COUNT(*) FROM #DDLAlertLog AL LEFT JOIN #AlterRules AR ON AL.CommandAction = replace(AR.AlertRule,' ','') WHERE AR.AlertRule is not null OR AL.CommandText like 'alter authorization%' IF @totAlerts > 0 BEGIN SET @mailImportance = 'High' END ELSE BEGIN SET @mailImportance = 'Normal' END IF @totDDL > 0 BEGIN SELECT @email = DML_Recipients FROM HCITools.dbo.DBA_Mailing_list WHERE DML_Code = 'DBA_operator' SET @subject = @format+@ou+': ' + convert(varchar,@totDDL) + ' DDL audit found: Database settings modified! - [' + @@SERVERNAME + ']' SET @HTML = N'Server: ' + @format+@ou+'
List of all DDL audit events (ALTER DATABASE) for the last day:

' + N'' + CAST(( SELECT CASE WHEN AR.AlertRule is null AND UPPER(AL.CommandText) not like 'ALTER AUTHORIZATION%' THEN 'INFO' ELSE 'CRITICAL' END AS 'td','',AL.DA_App_Name AS 'td','', DA_Host_Name AS 'td','', PostTime AS 'td','', SPID AS 'td','', ServerName AS 'td','', isnull(LoginName,'') AS 'td','', isnull(UserName,'') AS 'td','', isnull(DatabaseName,'') AS 'td','', isnull(SchemaName,'') AS 'td','', isnull(ObjectName,'') AS 'td','', isnull(ObjectType,'') AS 'td','', CommandText AS 'td' FROM #DDLAlertLog AL LEFT JOIN #AlterRules AR ON AL.CommandAction = replace(AR.AlertRule,' ','') FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX)) + N'
AlertLevelApplication NameHost NameModified dateSPIDServer NameLogin NameUser NameDatabase NameSchemaObjectTypeCommand
' ; /* Get default mailbox profile name */ DECLARE @defaultprofilname varchar(100) SELECT DISTINCT @defaultprofilname = p.name FROM msdb.dbo.sysmail_profile p JOIN msdb.dbo.sysmail_principalprofile pp ON pp.profile_id = p.profile_id AND pp.is_default = 1 /* SEND MAIL */ EXEC msdb.dbo.sp_send_dbmail @profile_name = @defaultprofilname, @recipients = @email, @body = @html, @importance = @mailImportance, @subject = @subject, @body_format = 'HTML'; END /* Drop temp tables */ DROP TABLE #DDLAlertLog DROP TABLE #AlterRules END TRY BEGIN CATCH SELECT @errno = 70003, @errmsg = 'error on sp_ddl_alerts! ' + error_message() goto error_99 END CATCH; /*------------------ Retour au programme appelant -----------------*/ RETURN(@@error); /*---------------------- Traitement des erreurs ----------------------*/ error_99: RAISERROR (@errmsg, 16, 1); RETURN(@errno); GO