Hey guys,
Good morning.
Today I come to bring you the solution to some questions that I asked myself in the environments where I work, but that I had no way of answering:
– Who created/changed/deleted a particular job?
– I accidentally deleted a Job. How do I recreate it quickly, without having to restore a backup?
– Someone disabled a certain Job. Who was it?
– Someone changed the Job description.. I need to identify who it was..
To answer these questions, we will create a way to monitor the creation, modification and deletion of Jobs in SQL Server, through a trigger in the msdb.dbo.sysjobs table.
Creating the history table
Before creating the trigger that will retrieve the information, we will need to create the table that will store the information and create the history.
CREATE TABLE [dbo].[Job_Audit] (
[Id_Auditoria] [INT] IDENTITY(1,1) PRIMARY KEY CLUSTERED NOT NULL,
[Dt_Evento] [DATETIME] NULL DEFAULT (GETDATE()),
[Ds_Usuario] [VARCHAR](50) NULL,
[Ds_Job] [sysname] NULL,
[Ds_Hostname] [VARCHAR](50) NULL,
[Ds_Query] [VARCHAR](MAX) NULL,
[Fl_Situacao] [TINYINT] NULL
)
WITH (DATA_COMPRESSION=PAGE)
Trigger creation
Now that we have created the table that will contain our information, let's create the trigger that will populate it.
USE [msdb]
GO
/***************************************************************************************************
-- Trigger para os Jobs
***************************************************************************************************/
IF ((SELECT COUNT(*) FROM sys.triggers WHERE name = 'trgJobs_Status') > 0) DROP TRIGGER dbo.trgJobs_Status
GO
CREATE TRIGGER trgJobs_Status ON sysjobs
AFTER INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON
DECLARE
@UserName VARCHAR(50) = SYSTEM_USER,
@HostName VARCHAR(50) = HOST_NAME(),
@JobName sysname,
@New_Enabled INT,
@Old_Enabled INT,
@ExecStr VARCHAR(100),
@Qry VARCHAR(MAX)
SELECT @New_Enabled = [enabled] FROM Inserted
SELECT @Old_Enabled = [enabled] FROM Deleted
SELECT @JobName = [name] FROM Deleted
IF (@JobName IS NULL)
SELECT @JobName = [name] FROM Deleted
-- Identificando a query executada
CREATE TABLE #inputbuffer (
[EventType] NVARCHAR(60),
[Parameters] INT,
[EventInfo] VARCHAR(MAX)
)
SET @ExecStr = 'DBCC INPUTBUFFER(' + STR(@@SPID) + ')'
INSERT INTO #inputbuffer
EXEC (@ExecStr)
SET @Qry = (SELECT EventInfo FROM #inputbuffer)
-- Verifica se houve alteração de status
IF (@New_Enabled != @Old_Enabled)
BEGIN
IF (@New_Enabled = 1)
BEGIN
INSERT INTO dbo.Job_Audit ( Ds_Usuario, Ds_Job, Ds_Hostname, Ds_Query, Fl_Situacao )
SELECT @UserName, @JobName, @HostName, @Qry, 1
END
IF (@New_Enabled = 0)
BEGIN
INSERT INTO dbo.Job_Audit ( Ds_Usuario, Ds_Job, Ds_Hostname, Ds_Query, Fl_Situacao )
SELECT @UserName, @JobName, @HostName, @Qry, 0
END
END
ELSE BEGIN
INSERT INTO dbo.Job_Audit ( Ds_Usuario, Ds_Job, Ds_Hostname, Ds_Query )
SELECT @UserName, @JobName, @HostName, @Qry
END
END
GO
/***************************************************************************************************
-- Trigger para os Schedules dos Jobs
***************************************************************************************************/
IF ((SELECT COUNT(*) FROM sys.triggers WHERE name = 'trgAudit_Schedules') > 0) DROP TRIGGER dbo.trgAudit_Schedules
GO
CREATE TRIGGER [dbo].[trgAudit_Schedules] ON [dbo].[sysschedules]
AFTER UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON
DECLARE
@UserName VARCHAR(50) = SYSTEM_USER,
@HostName VARCHAR(50) = HOST_NAME(),
@JobName VARCHAR(MAX) = '',
@ExecStr VARCHAR(100),
@Qry VARCHAR(MAX)
IF ((SELECT COUNT(*) FROM Inserted) > 0)
BEGIN
SELECT @JobName += (CASE WHEN @JobName != '' THEN ' | ' ELSE '' END) + A.[name]
FROM msdb.dbo.sysjobs A
JOIN msdb.dbo.sysjobschedules B ON A.job_id = B.job_id
JOIN Inserted C ON B.schedule_id = C.schedule_id
END
ELSE BEGIN
SELECT @JobName += (CASE WHEN @JobName != '' THEN ' | ' ELSE '' END) + A.[name]
FROM msdb.dbo.sysjobs A
JOIN msdb.dbo.sysjobschedules B ON A.job_id = B.job_id
JOIN Deleted C ON B.schedule_id = C.schedule_id
END
-- Identificando a query executada
CREATE TABLE #inputbuffer (
[EventType] NVARCHAR(60),
[Parameters] INT,
[EventInfo] VARCHAR(MAX)
)
SET @ExecStr = 'DBCC INPUTBUFFER(' + STR(@@SPID) + ')'
INSERT INTO #inputbuffer
EXEC (@ExecStr)
SET @Qry = (SELECT EventInfo FROM #inputbuffer)
IF (@JobName != '')
BEGIN
INSERT INTO dbo.Job_Audit ( Ds_Usuario, Ds_Job, Ds_Hostname, Ds_Query )
SELECT @UserName, @JobName, @HostName, @Qry
END
END
GO
ALTER TABLE [dbo].[sysschedules] ENABLE TRIGGER [trgAudit_Schedules]
GO
/***************************************************************************************************
-- Trigger para os Schedules
***************************************************************************************************/
IF ((SELECT COUNT(*) FROM sys.triggers WHERE name = 'trgAudit_Jobs_Schedules') > 0) DROP TRIGGER dbo.trgAudit_Jobs_Schedules
GO
CREATE TRIGGER [dbo].[trgAudit_Jobs_Schedules] ON [dbo].[sysjobschedules]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE
@UserName VARCHAR(50) = SYSTEM_USER,
@HostName VARCHAR(50) = HOST_NAME(),
@JobName sysname,
@ExecStr VARCHAR(100),
@Qry VARCHAR(MAX)
IF ((SELECT COUNT(*) FROM Inserted) > 0)
BEGIN
SELECT @JobName = A.[name]
FROM msdb.dbo.sysjobs A
JOIN Inserted B ON A.job_id = B.job_id
END
ELSE BEGIN
SELECT @JobName = A.[name]
FROM msdb.dbo.sysjobs A
JOIN Deleted B ON A.job_id = B.job_id
END
-- Identificando a query executada
CREATE TABLE #inputbuffer (
[EventType] NVARCHAR(60),
[Parameters] INT,
[EventInfo] VARCHAR(MAX)
)
SET @ExecStr = 'DBCC INPUTBUFFER(' + STR(@@SPID) + ')'
INSERT INTO #inputbuffer
EXEC (@ExecStr)
SET @Qry = (SELECT EventInfo FROM #inputbuffer)
INSERT INTO dbo.Job_Audit ( Ds_Usuario, Ds_Job, Ds_Hostname, Ds_Query )
SELECT @UserName, @JobName, @HostName, @Qry
END
GO
ALTER TABLE [dbo].[sysjobschedules] ENABLE TRIGGER [trgAudit_Jobs_Schedules]
GO
Querying the information
Now that our trigger is activated, make some changes to your Jobs and see how the information is recorded. It is possible to identify the date/time that the event was triggered, the user who performed the event and even the query that was executed in the database, whether to create, delete or change the Job.
Until later!

Comentários (0)
Carregando comentários…