Databases Speaker Wylie Blanchard - Keynote Business Technology Speaker - Workshops Social Mobile Analytics Cloud Wylie Blanchard | Business Technology Expert, Digital Executive Advisor & Speaker - Wylie Blanchard Mon, 04 Mar 2024 17:10:32 +0000 en-US hourly 1 /wp-content/uploads/cropped-Wylie-Blanchard-profile-photo_202008_IMG_7092_1100x1100-32x32.jpg Databases Speaker Wylie Blanchard - Keynote Business Technology Speaker - Workshops Social Mobile Analytics Cloud 32 32 61397150 UIUC Gies Business highlights Wylie Blanchard https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/uiuc-gies-business-mba-coursework-taught-me-to-focus-on-value/ Sun, 08 Nov 2020 07:14:00 +0000 https://www.wylieblanchard.com/?p=6046 I was recently featured in an article by the University of Illinois, Gies College of Business, highlighting what I learned as a student in the school’s Master of Business Administration (MBA) degree program and while attending global immersions in Germany and Brazil with my fellow MBA students. Here’s an excerpt from the article titled “Blanchard […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
logo for University of Illinois at Urbana-Champaign Gies College of Business

I was recently featured in an article by the University of Illinois, Gies College of Business, highlighting what I learned as a student in the school’s Master of Business Administration (MBA) degree program and while attending global immersions in Germany and Brazil with my fellow MBA students. Here’s an excerpt from the article titled “Blanchard Uses MBA Experience to Explore near-Shore Tech Options.” 1, 2, 3


Gies College of Business MBA student Wylie Blanchard’s love of technology runs deep. The founder of Chicago-based Great Tech Pros grew up taking apart everything from toasters to his first word processor to see how they worked. His company advises clients primarily in the healthcare and insurance services industries how to design tech solutions that create value for their customers.

Blanchard said the iMBA experience has also taught him to think more globally about how to grow Great Tech Pros, founded in 2013.

Blanchard is exploring setting up near-shore database operations with fellow iMBA student Paul Taylor in his Jamaica home base. He turned to Taylor to create a solution that had a US-friendly time zone when Great Tech Pros couldn’t meet a client’s price point with a US-based solution.

The Gies iMBA program isn’t Blanchard’s first experience with online learning. He received a BS degree in business administration and management from Walden University. Blanchard said interacting with more marketing, strategy and finance decision makers is what prompted him to consider getting a master’s degree.

Visit the University of Illinois at Urbana-Champaign, Gies College of Business, website to read the full article that includes my quoted statements.

Photo by Erin Randle: Wylie Blanchard, Gies College of Business - University of Illinois
Photo by Erin Randle: Wylie Blanchard, University of Illinois at Urbana-Champaign, Gies College of Business.

“Blanchard Uses MBA Experience to Explore Near-Shore Tech Options.” Gies College of Business, University of Illinois at Urbana-Champaign, 9 Oct. 2020, https://giesbusiness.illinois.edu/news/2020/10/09/blanchard-uses-mba-experience-to-explore-near-shore-tech-options.

“Blanchard Uses MBA Experience to Explore Near-Shore Tech Options.” IMBA, University of Illinois at Urbana-Champaign, 18 May 2021, https://onlinemba.illinois.edu/blanchard-uses-mba-experience-to-explore-near-shore-tech-options/.

“Blanchard Uses MBA Experience To Explore Near-Shore Tech Options.” Poets&Quants. 24 Feb. 2021, https://poetsandquants.com/2021/02/04/blanchard-uses-mba-experience-to-explore-near-shore-tech-options/

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
6046
Become a SQL Pro who’s in High Demand – Chicago IL 2018 https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/become-sql-pro-whos-high-demand-sql-saturday-chicago-2018/ Mon, 19 Mar 2018 07:50:38 +0000 https://www.wylieblanchard.com/?p=3116 EVENT UPDATE: The SQL Chicago community is always the best. I had a full house for this session and the audience participation was amazing. Feedback from the audience was that they enjoyed the discussion portion on scaling degrees and certifications to maximize the return on their investment. I didn’t originally plan to share my views on scalability but I’ll […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
RT @SQLBob: Become a #SQL Pro Who's in High Demand with @WylieBlanchard1 #SQLSatChicago
RT @SQLBob: Become a #SQL Pro Who’s in High Demand with @WylieBlanchard1 #SQLSatChicago

EVENT UPDATE: The SQL Chicago community is always the best. I had a full house for this session and the audience participation was amazing. Feedback from the audience was that they enjoyed the discussion portion on scaling degrees and certifications to maximize the return on their investment. I didn’t originally plan to share my views on scalability but I’ll definitely include it in my next session on this topic.

Notable Sessions: Here are two sessions that I attended that were great in both content and delivery.


Follow Up:

SESSION DESCRIPTION:

Become a SQL Pro who’s in High Demand

Speaker(s)Wylie Blanchard

Track: Professional Development

Expertise in SQL is an in-demand IT skill. As demand continues to grow, so does the increase of SQL professionals entering your specific industry. Learn what’s needed to ensure that you become a stronger technology authority in your industry and a SQL Pro who’s always in High Demand. You’ll learn how to invest in growing your expertise, improve your social/people skills, how to effectively sell and market your talent, what is a “source of truth” and why is it extremely important and more.

Session Materials for Event Attendees:

[pdf-embedder url=”https://www.wylieblanchard.com/wp-content/uploads/Become-a-SQL-Pro-who’s-in-High-Demand_SQL-Saturday-719_Chicago-2018_-Benedictine-University_Wylie-Blanchard.pdf” title=”Become a SQL Pro who’s in High Demand_SQL Saturday 719_Chicago 2018_ Benedictine University_Wylie Blanchard”]

Download: Presentation Slides


Cool slide deck, nice presentation and organization of content as well as an awesome story to be telling others at UGs and SQL Saturdays. Thanks for paying it forward!

— Tim Radney (@tradney) March 19, 2018


Benedictine-University_SQL-Saturday-Chicago-2018-Wylie-Blanchard

SQLSaturday is a training event for Microsoft Data Platform professionals and those wanting to learn about SQL Server, Business Intelligence and Analytics. This event was be held on Mar 17, 2018, at Benedictine University, 5700 College Rd, Lisle, Illinois, 60532, United States.

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
3116
Developing Business-Driven Self-Service BI – New York https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/new-york-2017-developing-business-driven-self-service-bi/ Sat, 27 May 2017 00:31:40 +0000 https://www.wylieblanchard.com/?p=2778 Continued from SQLSaturday #588 – New York City 2017. EVENT UPDATE: What an amazing audience at SQL Saturday NYC. Things started off shaky when we encountered technical issues with the video projector at the start of my presentation. After a few minutes of working with the AV staff we decided to cram into a nearby conference room with […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
SQLSaturday-588-New-York-City-2017_Wylie-Blanchard_b
RT @PatrickDBA: Watching @WylieBlanchard1 demo building tabular models at #sqlsatNYC

Continued from SQLSaturday #588 – New York City 2017.

EVENT UPDATE: What an amazing audience at SQL Saturday NYC. Things started off shaky when we encountered technical issues with the video projector at the start of my presentation. After a few minutes of working with the AV staff we decided to cram into a nearby conference room with a working projector and after grabbing a few extra chairs, with a few people standing, we were able to proceed and move the session along smoothly. Luckily, I only loss a few minutes of session time. I’m highly thankful that everyone stuck with me and didn’t leave to attend another session. Overall a great session, a great technical staff, and an even greater audience.

Session Description: 

Speaker(s): Wylie Blanchard

Duration: 70 minutes

Track: BI Platform Architecture, Development & Administration

In this session, we’ll develop a Tabular Data Model in MS SSAS and review our options for deploying, sharing and visualizing it.  Well also discuss how senior leaders will see the business value of SSAS and how end users can utilize it for Self-Service Business Intelligence.

Accompanying Materials:

[pdf-embedder url=”https://www.wylieblanchard.com/wp-content/uploads/Presentation_SSAS-Tabular-in-60-mins-Developing-Business-Driven-Self-Service-BI_2017_Wylie-Blanchard_Great-Tech-Pros3.pdf” title=”SSAS-Tabular-in-60-mins-Developing-Business-Driven-Self-Service-BI_2017_Wylie-Blanchard_Great-Tech-Pros”]

Download: Presentation Slides
Get the Demo Guide


SQLSaturday-588_Microsoft_New-York-City-2017_Great-TechPros_Wylie-Blanchard[1]

SQLSaturday is a training event for Microsoft Data Platform professionals and those wanting to learn about SQL Server, Business Intelligence, and Analytics. This event was held on May 20, 2017, at Microsoft New York Metro District Office, 11 Times Square, New York City, New York, 10036, United States

 

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
2778
SQL Saturday Chicago 2017 https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/sql-saturday-chicago-2017/ Mon, 27 Feb 2017 07:09:38 +0000 https://www.wylieblanchard.com/?post_type=events&p=2794 Analyzing SQL Server Data using PowerPivot in MS Excel Speaker(s): Wylie Blanchard Duration: 60 minutes Track: BI Information Delivery Your end users want to analyze data in your data warehouse. They could deal with the learning curve of SSAS but they’d prefer to utilize a familiar application like MS Excel. Welcome, PowerPivot, a tool that […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>

Speaker(s): Wylie Blanchard

Duration: 60 minutes

Track: BI Information Delivery

Your end users want to analyze data in your data warehouse. They could deal with the learning curve of SSAS but they’d prefer to utilize a familiar application like MS Excel. Welcome, PowerPivot, a tool that retrieves data from your data warehouse by combining the power of SSAS models and your SQL Server Data warehouse within the familiar interface of MS Excel. In this presentation well explore SSAS BI Semantic model, PowerView, PowerPivot in Excel.

 

The event resources for this session are now available. 


SQLSaturday-600-Chicago-2017-Devry-University[1]SQLSaturday is a training event for Microsoft Data Platform professionals and those wanting to learn about SQL Server, Business Intelligence, and Analytics. This event will be held on Mar 11, 2017, at DeVry University – Addison Campus, 1221 North Swift Road, Addison, Illinois, 60101, United States

 

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
2794
Chicago SQL BI User Group March 2017 – @CNUG_ https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/chicago-sql-bi-user-group-march-2017_cnug/ Mon, 27 Feb 2017 07:01:42 +0000 https://www.wylieblanchard.com/?post_type=events&p=2789 Upcoming event:  Self Service BI With a Tool End Users Already Know & Love Speaker(s): Wylie Blanchard Duration: 60 minutes Track: BI Information Delivery Your end users want to analyze data in your data warehouse. They want it yesterday and they want to do it themselves so that it’s done “right”. Welcome, PowerPivot, a tool […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
Upcoming event: 

Speaker(s): Wylie Blanchard

Duration: 60 minutes

Track: BI Information Delivery

Your end users want to analyze data in your data warehouse. They want it yesterday and they want to do it themselves so that it’s done “right”. Welcome, PowerPivot, a tool that analyzes data from your data warehouse by combining the power of Analysis Services models and your SQL Server Data warehouse within the familiar interface of MS Excel. In this presentation well explore the Analysis Services BI Semantic model & PowerPivot in Excel… Love, Like or hate Excel – Your end users are familiar with it and PowerPivot is the best thing to happen to it in years.

Event resources from this session are now available. 


The Chicago SQL BI User Group hosts monthly meetings for SQL and Business Intelligence professionals to meet, learn, and network. Speakers present a different topic each month covering both SQL BI topics and relevant non-SQL technologies. Dinner, refreshments, and door prizes are provided by sponsors. This meeting will be held on Saturday, March 15, 2017, 6:00 PM at Microsoft Technical Center, 200 E Randolph St. Suite 200, Chicago, IL 60601.

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
2789
PCP Member Eligibility Secure Email https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/pcp-member-eligibility-secure-email-spiceworks/ Mon, 30 May 2016 04:57:33 +0000 https://www.wylieblanchard.com/?p=1835 Automated, Hippa Compliant, system to email member eligibility lists to Primary Care Physicians. Trizetto’s QNXT™ Enterprise Core Administration System & ASM’s MD-Staff – Credentialing. Created an automated, HIPAA compliant, process to securely batch and distribute member eligibility lists to PMG/non-Presence PCP’s on a monthly basis via individual PCP email addresses.Utilizing SQL, SSIS, & C#,: Trizetto’s […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
Automated, Hippa Compliant, system to email member eligibility lists to Primary Care Physicians. Trizetto’s QNXT™ Enterprise Core Administration System & ASM’s MD-Staff – Credentialing.
Created an automated, HIPAA compliant, process to securely batch and distribute member eligibility lists to PMG/non-Presence PCP’s on a monthly basis via individual PCP email addresses.Utilizing SQL, SSIS, & C#,: Trizetto’s QNXT™ Enterprise Core Administration System & ASM’s MD-Staff – Credentialing

 

Des Plaines, Illinois
Des Plaines, Illinois

COMPLETION DATE: April 29th, 2016

Technology Used

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
1835
Remote DBA – Database Administration: @ SpiceWorks https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/remote-dba-database-administration-spiceworks/ Sun, 01 May 2016 23:06:06 +0000 https://www.wylieblanchard.com/?p=1822 Remote SQL Server Administration Managing several versions of MS SQL Server 2005-2014 Also managing Oracle 11g Managing and maintaining databases and servers for multiple clients – backups, log shipping, replication, mirroring, Always On availability groups, and clustering. Configuring and troubleshooting multiple versions of MS SQL Server – 2005, 2008, 2008 R2, 2012, 2014. Performing migrations, […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
Remote SQL Server Administration

Managing several versions of MS SQL Server 2005-2014

Also managing Oracle 11g

Managing and maintaining databases and servers for multiple clients – backups, log shipping, replication, mirroring, Always On availability groups, and clustering.

Configuring and troubleshooting multiple versions of MS SQL Server – 2005, 2008, 2008 R2, 2012, 2014.

Performing migrations, refreshes and restores for multiple clients.

Configuring maintenance and optimization tasks – index maintenance and backups via maintenance plans.

Provide planning and/or implementation support for SQL Server projects as well as required business support of current SQL Server database environments.

Work with client leadership in the enhancement and security of database, server and application development initiatives.

Provide off shift support for junior DBA teams.

Develop solutions to support database consolidation and centralization of existing applications from remote locations .

Provide and share technical expertise with the client teams on security, backup/recovery, performance tuning, extract transform load strategies, report development and business intelligence development.

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
1822
Simple Audit of SQL Server Agent: @SpiceWorks https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/simple-audit-sql-server-agent-spiceworks/ Fri, 18 Mar 2016 12:37:47 +0000 https://www.wylieblanchard.com/?p=1613 Who Changed My SQL Server Agent Job? Created process and ssrs report to audit changes to SQL Server Agent Jobs on SQL Server 2008 R2. Created process using SSRS, SSMS, T-SQL, SQL Triggers. Created and implemented process to audit changes to SQL Server Agent Jobs on SQL Server 2008 R2. Created a new schema and […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
Who Changed My SQL Server Agent Job?

Created process and ssrs report to audit changes to SQL Server Agent Jobs on SQL Server 2008 R2. Created process using SSRS, SSMS, T-SQL, SQL Triggers.

Created and implemented process to audit changes to SQL Server Agent Jobs on SQL Server 2008 R2. Created a new schema and table structure to capture audit data for agent jobs. Created triggers on the sysjobs, sysjobsteps, sysjobschedule tables that captured imports, updates and deletes made to sql server agent jobs and then loaded the data, as well as the user realted to the activity, to the newly created audit table. I also created a SSRS report that allowed the Information Services team to view the audit data.

1 Week Duration
1-49 Users
1-49 Devices

 

/** Description : Create SQL Angent Jobs Audit Process without SQL Servers “Audit” feature
Author : Wylie Blanchard
Date : 2016/02/12 Updated : 2016/03/18 **/
/** Create Schema [audit]**/
USE [AuditDB]
GO
CREATE SCHEMA [audit] AUTHORIZATION [dbo]
GO
/** Create table [audit].[SQLJobModificationHistory]**/
USE [AuditDB]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [audit].[SQLJobModificationHistory](
[EventRowID] [bigint] IDENTITY(1,1) NOT NULL,
[EventTime] [datetime] NULL,
[EventType] [varchar](128) NULL,
[Message] [varchar](max) NULL,
[HostName] [varchar](128) NULL,
[Instance] [varchar](128) NULL,
[JobID] [varchar](256) NULL,
[JobName] [varchar](256) NULL,
[OldJobName] [varchar](256) NULL,
[JobCreationDate] [datetime] NULL,
[JobModificationDate] [datetime] NULL,
[AuditUser] [varchar](128) NULL,
[SessionLoginName] [varchar](256) NULL,
[AuditDate] [smalldatetime] NOT NULL,
CONSTRAINT [PK_SQLJobModificationHistory_EventRowID] PRIMARY KEY NONCLUSTERED
(
[EventRowID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [audit].[SQLJobModificationHistory] ADD CONSTRAINT [DF_SQLJobModificationHistory_SessionLoginName] DEFAULT (original_login()) FOR [SessionLoginName]
GO

ALTER TABLE [audit].[SQLJobModificationHistory] ADD CONSTRAINT [DF_SQLJobModificationHistory_AuditDate] DEFAULT (getdate()) FOR [AuditDate]
GO

/** Create Audit Triggers on SysJobs**/

— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditNewSQLAgentJobTrigger
— =============================================
USE [msdb]
GO
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditNewSQLAgentJobTrigger]
ON [msdb].[dbo].[sysjobs]
FOR INSERT

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@NewJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]

SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @NewJobName = [name] FROM Inserted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted
SELECT @DateJobModified = [date_modified] FROM Inserted
IF(SELECT COUNT([name]) FROM [master].[dbo].[sysdatabases]
WHERE [name] IN (‘AuditDB’)
AND [status]&32 <> 32 AND [status]&256 <> 256
AND [status]&32768 <> 32768
AND DATABASEPROPERTYEX([name],’Status’) NOT IN ( ‘OFFLINE’
,’RESTORING’
,’RECOVERING’
,’SUSPECT’) ) = 1
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’JOB_CREATED’
,CAST ( ‘User “‘+@UserName+'” has created SQL job “‘+@NewJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditModifiedSQLAgentJobTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditModifiedSQLAgentJobTrigger]
ON [msdb].[dbo].[sysjobs]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]

SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @NewJobName = [name] FROM Inserted
SELECT @OldJobName = [name] FROM Deleted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted
SELECT @DateJobModified = [date_modified] FROM Inserted
IF(SELECT COUNT([name]) FROM [master].[dbo].[sysdatabases]
WHERE [name] IN (‘AuditDB’)
AND [status]&32 <> 32 AND [status]&256 <> 256
AND [status]&32768 <> 32768
AND DATABASEPROPERTYEX([name],’Status’) NOT IN ( ‘OFFLINE’
,’RESTORING’
,’RECOVERING’
,’SUSPECT’) ) = 1
BEGIN
IF (@NewJobName is not null and @OldJobName is not null) and (@NewJobName <> @OldJobName)
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’JOB_MODIFIED’
, CAST ( ‘User “‘+@UserName+'” has modified job “‘+@OldJobName+'” with “‘
+@NewJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditDeletedSQLAgentJobTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditDeletedSQLAgentJobTrigger]
ON [msdb].[dbo].[sysjobs]
FOR DELETE
AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON

DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@OldJobID [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]

SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @OldJobID = [job_id] FROM Deleted
SELECT @OldJobName = [name] FROM Deleted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Deleted
SELECT @DateJobModified = [date_modified] FROM Deleted

IF(SELECT COUNT([name]) FROM [master].[dbo].[sysdatabases]
WHERE [name] IN (‘AuditDB’)
AND [status]&32 <> 32 AND [status]&256 <> 256
AND [status]&32768 <> 32768
AND DATABASEPROPERTYEX([name],’Status’) NOT IN ( ‘OFFLINE’
,’RESTORING’
,’RECOVERING’
,’SUSPECT’) ) = 1
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’JOB_DELETED’
,CAST ( ‘User “‘+@UserName+'” has deleted SQL job “‘+@OldJobName+'” from “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@OldJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditSQLAgentJobActivationTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditSQLAgentJobActivationTrigger]
ON [msdb].[dbo].[sysjobs]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewEnabled [int]
,@OldEnabled [int]

SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @NewJobName = [name] FROM Inserted
SELECT @OldJobName = [name] FROM Deleted
SELECT @NewEnabled = [enabled] FROM Inserted
SELECT @OldEnabled = [enabled] FROM Deleted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted
SELECT @DateJobModified = [date_modified] FROM Inserted

— check if the enabled flag has been updated.
IF @NewEnabled <> @OldEnabled
BEGIN
IF(SELECT COUNT([name]) FROM [master].[dbo].[sysdatabases]
WHERE [name] IN (‘AuditDB’)
AND [status]&32 <> 32 AND [status]&256 <> 256
AND [status]&32768 <> 32768
AND DATABASEPROPERTYEX([name],’Status’) NOT IN ( ‘OFFLINE’
,’RESTORING’
,’RECOVERING’
,’SUSPECT’) ) = 1
BEGIN
IF @NewEnabled = 1
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’JOB_ENABLED’
,CAST ( ‘User “‘+@UserName+'” has enabled SQL job “‘+@NewJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END — End of inner-IF block…
IF @NewEnabled = 0
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’JOB_DISABLED’
,CAST ( ‘User “‘+@UserName+'” has disabled SQL job “‘+@NewJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END — End of inner-IF block…
END — End of outer-IF block…
END — End of outer-IF block…
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END

GO
/** Create Audit Triggers on SysJobSteps**/

— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditNewSQLAgentJobStepTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditNewSQLAgentJobStepTrigger]
ON [msdb].[dbo].[sysjobsteps]
FOR INSERT

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@NewJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewStepName [varchar] (128)
,@New_cmd [varchar](MAX)
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [date_modified] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @NewStepName = [step_name] FROM Inserted
SELECT @New_cmd = ISNULL(command,’– Not Applicable –’) FROM Inserted
SELECT @NewJobName = name
FROM sysjobsteps a, sysjobs b
WHERE a.job_id = b.job_id
AND b.job_id = @NewJobID

BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’STEP_CREATED’
, CAST ( ‘User “‘+@UserName+'” has created job step “‘+@NewStepName+'” of SQL Job “‘
+@NewJobName+'” from host “‘+@HostName+'” at ‘+CONVERT(VARCHAR(20),GETDATE(),100)
+’ New command is “‘+@New_cmd+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)

END
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditModifiedSQLAgentJobStepTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditModifiedSQLAgentJobStepTrigger]
ON [msdb].[dbo].[sysjobsteps]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@OldJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewStepId [varchar] (40)
,@OldStepId [varchar] (40)
,@NewStepName [varchar] (128)
,@OldStepName [varchar] (128)
,@NewSubSystem [varchar] (40)
,@OldSubSystem [varchar] (40)
,@New_cmd [varchar](MAX)
,@Old_cmd [varchar](MAX)
,@Bodytext VARCHAR(2000)
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @OldJobID = [job_id] FROM Deleted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [date_modified] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @NewStepId = [step_id] FROM Inserted
SELECT @OldStepId = [step_id] FROM Deleted
SELECT @NewStepName = [step_name] FROM Inserted
SELECT @OldStepName = [step_name] FROM Deleted
SELECT @NewSubSystem = [subsystem] FROM Inserted
SELECT @OldSubSystem = [subsystem] FROM Deleted
SELECT @New_cmd = ISNULL(command,’– Not Applicable –’) FROM Inserted
SELECT @Old_cmd = ISNULL(command,’– Not Applicable –’) FROM Deleted
SELECT @NewJobName = name FROM sysjobsteps a, sysjobs b WHERE a.job_id = b.job_id AND b.job_id = @NewJobID
SELECT @OldJobName = name FROM sysjobsteps a, sysjobs b WHERE a.job_id = b.job_id AND b.job_id = @OldJobID

IF @NewStepName <> @OldStepName
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’STEP_MODIFIED’
,–CAST ( ‘StepID=”‘ + @StepId + ‘”‘ +
–‘, StepName=”‘ + @StepName + ‘”‘ +
–‘, SubSystem=”‘ + @SubSystem + ‘”‘ +
— ‘, Command=”‘ + @Command + ‘”‘ AS varchar(max))

CAST ( ‘User “‘+@UserName+'” has modified job step “‘+@OldStepName+'” with “‘
+@NewStepName+'” of SQL Job “‘+@NewJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’. Old command is “‘+@Old_cmd+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END

GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditDeletedSQLAgentJobStepTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditDeletedSQLAgentJobStepTrigger]
ON [msdb].[dbo].[sysjobsteps]
FOR DELETE
AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON

DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@OldJobID [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@OldStepId [varchar] (40)
,@OldStepName [varchar] (128)
,@SubSystem [varchar] (40)
,@Old_cmd [varchar](MAX)

SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @OldJobID = [job_id] FROM Deleted
SELECT @OldJobName = [name] FROM Deleted LEFT JOIN [sysjobs] ON Deleted.[job_id] = [sysjobs].[job_id]
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Deleted LEFT JOIN [sysjobs] ON Deleted.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [date_modified] FROM Deleted LEFT JOIN [sysjobs] ON Deleted.[job_id] = [sysjobs].[job_id]
SELECT @OldStepId = [step_id] FROM Deleted
SELECT @OldStepName = [step_name] FROM Deleted
SELECT @SubSystem = [subsystem] FROM Deleted
SELECT @Old_cmd = ISNULL(command,’– Not Applicable –’) FROM Deleted

IF(SELECT COUNT([name]) FROM [master].[dbo].[sysdatabases]
WHERE [name] IN (‘AuditDB’)
AND [status]&32 <> 32 AND [status]&256 <> 256
AND [status]&32768 <> 32768
AND DATABASEPROPERTYEX([name],’Status’) NOT IN ( ‘OFFLINE’
,’RESTORING’
,’RECOVERING’
,’SUSPECT’) ) = 1
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’STEP_DELETED’
, CAST ( ‘User “‘+@UserName+'” has deleted job step “‘+@OldStepName+'” of SQL Job “‘+@OldJobName+'” from host “‘
+@HostName+'” at ‘+CONVERT(VARCHAR(20),GETDATE(),100) +’ with command “‘+@Old_cmd+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@OldJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END
COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditModifiedSQLAgentJobStepCmdTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditModifiedSQLAgentJobStepCmdTrigger]
ON [msdb].[dbo].[sysjobsteps]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@OldJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewStepId [varchar] (40)
,@OldStepId [varchar] (40)
,@NewStepName [varchar] (128)
,@OldStepName [varchar] (128)
,@NewSubSystem [varchar] (40)
,@OldSubSystem [varchar] (40)
,@New_cmd [varchar](MAX)
,@Old_cmd [varchar](MAX)
,@Bodytext VARCHAR(2000)
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM Inserted
SELECT @OldJobID = [job_id] FROM Deleted
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [date_created] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [date_modified] FROM Inserted INNER JOIN [sysjobs] ON Inserted.[job_id] = [sysjobs].[job_id]
SELECT @NewStepId = [step_id] FROM Inserted
SELECT @OldStepId = [step_id] FROM Deleted
SELECT @NewStepName = [step_name] FROM Inserted
SELECT @OldStepName = [step_name] FROM Deleted
SELECT @NewSubSystem = [subsystem] FROM Inserted
SELECT @OldSubSystem = [subsystem] FROM Deleted
SELECT @New_cmd = ISNULL(command,’– Not Applicable –’) FROM Inserted
SELECT @Old_cmd = ISNULL(command,’– Not Applicable –’) FROM Deleted
SELECT @NewJobName = name FROM sysjobsteps a, sysjobs b WHERE a.job_id = b.job_id AND b.job_id = @NewJobID
SELECT @OldJobName = name FROM sysjobsteps a, sysjobs b WHERE a.job_id = b.job_id AND b.job_id = @OldJobID

IF @New_cmd <> @old_cmd –Change to Command
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’STEP_CMD_MODIFIED’
,CAST ( ‘User “‘+@UserName+'” has modified job step “‘+@OldStepName
+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’. Old command is “‘+@Old_cmd+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END

GO
/** Create Audit Triggers on SysJobSchedules**/

— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditNewSQLAgentJobScheduleTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditNewSQLAgentJobScheduleTrigger]
ON [msdb].[dbo].[sysjobschedules]
FOR INSERT

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@NewJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewScheduleName [varchar] (128)
,@NewFrequency [varchar](MAX)
,@NewScheduleID [int]
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM INSERTED
—–
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [sysjobs].[date_created] FROM INSERTED LEFT JOIN [sysjobs] ON INSERTED.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [sysjobs].[date_modified] FROM INSERTED LEFT JOIN [sysjobs] ON INSERTED.[job_id] = [sysjobs].[job_id]
SELECT @NewScheduleName = [name] FROM INSERTED LEFT JOIN [sysschedules] on INSERTED.[schedule_id] = [sysschedules].[schedule_id]
SELECT @NewFrequency = RTRIM(CAST ( CASE [freq_type] WHEN 1 THEN ‘Occurs Only Once’ WHEN 4 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ day(s)’ WHEN 8 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ weeks(s) on ‘ + LEFT( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END , LEN( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END ) – 1 ) WHEN 16 THEN ‘Occurs Day ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ WHEN 32 THEN ‘Occurs on the ‘ + CASE [freq_relative_interval] WHEN 1 THEN ‘First’ WHEN 2 THEN ‘Second’ WHEN 4 THEN ‘Third’ WHEN 8 THEN ‘Fourth’ WHEN 16 THEN ‘Last’ END + CASE [freq_interval] WHEN 1 THEN ‘ Sunday’ WHEN 2 THEN ‘ Monday’ WHEN 3 THEN ‘ Tuesday’ WHEN 4 THEN ‘ Wednesday’ WHEN 5 THEN ‘ Thursday’ WHEN 6 THEN ‘ Friday’ WHEN 7 THEN ‘ Saturday’ WHEN 8 THEN ‘ Day’ WHEN 9 THEN ‘ Weekday’ WHEN 10 THEN ‘ Weekend Day’ END + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ ELSE ” END + ‘ ‘+ CASE [freq_subday_type] WHEN 1 THEN ‘at ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 2 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Seconds(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 4 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Minute(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 8 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Hour(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) ELSE ” END as varchar(max) ))
FROM INSERTED LEFT JOIN [sysschedules] on INSERTED.[schedule_id] = [sysschedules].[schedule_id]
SELECT @NewJobName = [sysjobs].name FROM INSERTED LEFT JOIN [sysjobs] ON INSERTED.[job_id] = [sysjobs].[job_id]
IF @NewScheduleName is not null
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_CREATED’
,CAST ( ‘User “‘+@UserName+'” has created job schedule “‘
+@NewScheduleName+'” of SQL Job “‘+@NewJobName+'” from host “‘+@HostName +'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’ New frequency is “‘+@NewFrequency+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@NewJobID
,@NewJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditDeleteSQLAgentJobScheduleTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditDeleteSQLAgentJobScheduleTrigger]
ON [msdb].[dbo].[sysjobschedules]
FOR DELETE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@OldJobID [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@OldScheduleName [varchar] (128)
,@OldFrequency [varchar](MAX)
,@OldScheduleID [int]
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @OldJobID = [job_id] FROM DELETED
—–
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [sysjobs].[date_created] FROM DELETED LEFT JOIN [sysjobs] ON DELETED.[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [sysjobs].[date_modified] FROM DELETED LEFT JOIN [sysjobs] ON DELETED.[job_id] = [sysjobs].[job_id]
SELECT @OldScheduleName = [name] FROM DELETED LEFT JOIN [sysschedules] on DELETED.[schedule_id] = [sysschedules].[schedule_id]
SELECT @OldFrequency = RTRIM(CAST ( CASE [freq_type] WHEN 1 THEN ‘Occurs Only Once’ WHEN 4 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ day(s)’ WHEN 8 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ weeks(s) on ‘ + LEFT( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END , LEN( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END ) – 1 ) WHEN 16 THEN ‘Occurs Day ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ WHEN 32 THEN ‘Occurs on the ‘ + CASE [freq_relative_interval] WHEN 1 THEN ‘First’ WHEN 2 THEN ‘Second’ WHEN 4 THEN ‘Third’ WHEN 8 THEN ‘Fourth’ WHEN 16 THEN ‘Last’ END + CASE [freq_interval] WHEN 1 THEN ‘ Sunday’ WHEN 2 THEN ‘ Monday’ WHEN 3 THEN ‘ Tuesday’ WHEN 4 THEN ‘ Wednesday’ WHEN 5 THEN ‘ Thursday’ WHEN 6 THEN ‘ Friday’ WHEN 7 THEN ‘ Saturday’ WHEN 8 THEN ‘ Day’ WHEN 9 THEN ‘ Weekday’ WHEN 10 THEN ‘ Weekend Day’ END + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ ELSE ” END + ‘ ‘+ CASE [freq_subday_type] WHEN 1 THEN ‘at ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 2 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Seconds(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 4 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Minute(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 8 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Hour(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) ELSE ” END as varchar(max) ))
FROM DELETED LEFT JOIN [sysschedules] on DELETED.[schedule_id] = [sysschedules].[schedule_id]
SELECT @OldJobName = [sysjobs].name FROM DELETED LEFT JOIN [sysjobs] ON DELETED.[job_id] = [sysjobs].[job_id]
IF @OldScheduleName is not null
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_DELETED’
,CAST ( ‘User “‘+@UserName+'” has deleted job schedule “‘
+@OldScheduleName+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName +'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’ Old frequency is “‘+@OldFrequency+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@OldJobName
,’– Not Applicable –’
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END
GO
/** Create Audit Triggers on SysSchedules**/

— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditUpdateSQLAgentJobScheduleTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditUpdateSQLAgentJobScheduleTrigger]
ON [msdb].[dbo].[sysschedules]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@OldJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewScheduleName [varchar] (128)
,@OldScheduleName [varchar] (128)
,@NewFrequency [varchar](MAX)
,@OldFrequency [varchar](MAX)
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id]
SELECT @OldJobID = [job_id] FROM DELETED LEFT JOIN [sysjobschedules] ON DELETED.[schedule_id]= [sysjobschedules].[schedule_id]
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [sysjobs].[date_created] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [sysjobs].[date_modified] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @NewScheduleName = [name] FROM INSERTED
SELECT @OldScheduleName = [name] FROM DELETED
SELECT @NewFrequency = RTRIM(CAST ( CASE [freq_type] WHEN 1 THEN ‘Occurs Only Once’ WHEN 4 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ day(s)’ WHEN 8 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ weeks(s) on ‘ + LEFT( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END , LEN( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END ) – 1 ) WHEN 16 THEN ‘Occurs Day ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ WHEN 32 THEN ‘Occurs on the ‘ + CASE [freq_relative_interval] WHEN 1 THEN ‘First’ WHEN 2 THEN ‘Second’ WHEN 4 THEN ‘Third’ WHEN 8 THEN ‘Fourth’ WHEN 16 THEN ‘Last’ END + CASE [freq_interval] WHEN 1 THEN ‘ Sunday’ WHEN 2 THEN ‘ Monday’ WHEN 3 THEN ‘ Tuesday’ WHEN 4 THEN ‘ Wednesday’ WHEN 5 THEN ‘ Thursday’ WHEN 6 THEN ‘ Friday’ WHEN 7 THEN ‘ Saturday’ WHEN 8 THEN ‘ Day’ WHEN 9 THEN ‘ Weekday’ WHEN 10 THEN ‘ Weekend Day’ END + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ ELSE ” END + ‘ ‘+ CASE [freq_subday_type] WHEN 1 THEN ‘at ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 2 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Seconds(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 4 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Minute(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 8 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Hour(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) ELSE ” END as varchar(max) ))
FROM INSERTED
SELECT @OldFrequency = RTRIM(CAST ( CASE [freq_type] WHEN 1 THEN ‘Occurs Only Once’ WHEN 4 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ day(s)’ WHEN 8 THEN ‘Occurs Every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ weeks(s) on ‘ + LEFT( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END , LEN( CASE WHEN [freq_interval] & 1 = 1 THEN ‘Sunday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 2 = 2 THEN ‘Monday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 4 = 4 THEN ‘Tuesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 8 = 8 THEN ‘Wednesday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 16 = 16 THEN ‘Thursday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 32 = 32 THEN ‘Friday, ‘ ELSE ” END + CASE WHEN [freq_interval] & 64 = 64 THEN ‘Saturday, ‘ ELSE ” END ) – 1 ) WHEN 16 THEN ‘Occurs Day ‘ + CONVERT(VARCHAR, [freq_interval]) + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ WHEN 32 THEN ‘Occurs on the ‘ + CASE [freq_relative_interval] WHEN 1 THEN ‘First’ WHEN 2 THEN ‘Second’ WHEN 4 THEN ‘Third’ WHEN 8 THEN ‘Fourth’ WHEN 16 THEN ‘Last’ END + CASE [freq_interval] WHEN 1 THEN ‘ Sunday’ WHEN 2 THEN ‘ Monday’ WHEN 3 THEN ‘ Tuesday’ WHEN 4 THEN ‘ Wednesday’ WHEN 5 THEN ‘ Thursday’ WHEN 6 THEN ‘ Friday’ WHEN 7 THEN ‘ Saturday’ WHEN 8 THEN ‘ Day’ WHEN 9 THEN ‘ Weekday’ WHEN 10 THEN ‘ Weekend Day’ END + ‘ of every ‘ + CONVERT(VARCHAR, [freq_recurrence_factor]) + ‘ month(s)’ ELSE ” END + ‘ ‘+ CASE [freq_subday_type] WHEN 1 THEN ‘at ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 2 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Seconds(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 4 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Minute(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) WHEN 8 THEN ‘ every ‘ + CONVERT(VARCHAR, [freq_subday_interval]) + ‘ Hour(s) between ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_start_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) + ‘ and ‘ + STUFF(STUFF(RIGHT(‘000000’ + CONVERT(VARCHAR(8), [active_end_time]), 6), 5, 0, ‘:’), 3, 0, ‘:’) ELSE ” END as varchar(max) ))
FROM DELETED
SELECT @NewJobName = [sysjobs].name FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @OldJobName = [sysjobs].name FROM DELETED LEFT JOIN [sysjobschedules] ON DELETED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
IF (@NewScheduleName is not null and @OldScheduleName is not null) and (@NewScheduleName <> @OldScheduleName) and (@NewFrequency = @OldFrequency) –Change to Schedule Name but no change to Frequency
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_MODIFIED’
,CAST ( ‘User “‘+@UserName+'” has modified job schedule “‘+@OldScheduleName+'” with “‘
+@NewScheduleName+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

IF (@NewScheduleName is not null and @OldScheduleName is not null) and (@NewScheduleName = @OldScheduleName) and ( @NewFrequency is not null and @OldFrequency is null) –No Change to Schedule Name but a new Frequency is added when it was previouslly null
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_MODIFIED’
,CAST ( ‘User “‘+@UserName+'” has modified job schedule “‘
+@OldScheduleName+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’ Old frequency is “‘+@OldFrequency+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

IF (@NewScheduleName is not null and @OldScheduleName is not null) and (@NewScheduleName = @OldScheduleName) and ( @NewFrequency is not null and @OldFrequency is not null) and (@NewFrequency <> @OldFrequency) –No Change to Schedule Name but change to Frequency
BEGIN

INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_MODIFIED’
,CAST ( ‘User “‘+@UserName+'” has modified job schedule “‘
+@OldScheduleName+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’ Old frequency is “‘+@OldFrequency+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
End

IF (@NewScheduleName is not null and @OldScheduleName is not null) and (@NewScheduleName <> @OldScheduleName) and (@NewFrequency <> @OldFrequency) –Change to Schedule Name and change to Frequency
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_MODIFIED’
,CAST ( ‘User “‘+@UserName+'” has modified job schedule “‘+@OldScheduleName+'” with “‘
+@NewScheduleName+'” of SQL Job “‘+@OldJobName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) +’ Old frequency is “‘+@OldFrequency+'”‘ AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END

GO
— =============================================
— Author: <Wylie Blanchard>
— Create date: <2016-02-15>
— Description: –Create Trigger AuditUpdateSQLAgentJobScheduleActivationTrigger
— =============================================
USE [msdb]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[AuditUpdateSQLAgentJobScheduleActivationTrigger]
ON [msdb].[dbo].[sysschedules]
FOR UPDATE

AS BEGIN

BEGIN TRY

BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE
@UserName [varchar](256)
,@SessionLogin [varchar](128)
,@HostName [varchar](128)
,@NewJobID [varchar](256)
,@OldJobID [varchar](256)
,@NewJobName [varchar](256)
,@OldJobName [varchar](256)
,@SQLInstance [varchar](128)
,@DateJobCreated [datetime]
,@DateJobModified [datetime]
,@NewScheduleName [varchar] (128)
,@OldScheduleName [varchar] (128)
,@NewEnabled [int]
,@OldEnabled [int]
SELECT @UserName = SYSTEM_USER
SELECT @SessionLogin = ORIGINAL_LOGIN()
SELECT @HostName = HOST_NAME()
SELECT @NewJobID = [job_id] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id]
SELECT @OldJobID = [job_id] FROM DELETED LEFT JOIN [sysjobschedules] ON DELETED.[schedule_id]= [sysjobschedules].[schedule_id]
SELECT @NewJobName = [sysjobs].name FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @OldJobName = [sysjobs].name FROM DELETED LEFT JOIN [sysjobschedules] ON DELETED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @NewEnabled = [enabled] FROM Inserted
SELECT @OldEnabled = [enabled] FROM DELETED
SELECT @SQLInstance = CONVERT([varchar](128), SERVERPROPERTY(‘ServerName’))
SELECT @DateJobCreated = [sysjobs].[date_created] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @DateJobModified = [sysjobs].[date_modified] FROM INSERTED LEFT JOIN [sysjobschedules] ON INSERTED.[schedule_id]= [sysjobschedules].[schedule_id] INNER JOIN [sysjobs] ON [sysjobschedules].[job_id] = [sysjobs].[job_id]
SELECT @NewScheduleName = [name] FROM INSERTED
SELECT @OldScheduleName = [name] FROM DELETED

— check if the enabled flag has been updated.
IF @NewEnabled <> @OldEnabled
BEGIN
IF @NewEnabled = 1
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_ENABLED’
,CAST ( ‘User “‘+@UserName+'” has enabled job schedule “‘+@NewScheduleName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END — End of inner-IF block…
IF @NewEnabled = 0
BEGIN
INSERT INTO [AuditDB].[audit].[SQLJobModificationHistory]
([EventTime]
,[EventType]
,[Message]
,[HostName]
,[Instance]
,[JobID]
,[JobName]
,[OldJobName]
,[JobCreationDate]
,[JobModificationDate]
,[AuditUser]
,[SessionLoginName])
VALUES
(GETDATE()
,’SCHEDULE_DISABLED’
,CAST ( ‘User “‘+@UserName+'” has disabled job schedule “‘+@NewScheduleName+'” from host “‘+@HostName+'” at ‘
+CONVERT(VARCHAR(20),GETDATE(),100) AS varchar(max))
,@HostName
,@SQLInstance
,@OldJobID
,@NewJobName
,@OldJobName
,@DateJobCreated
,@DateJobModified
,@UserName
,@SessionLogin)
END — End of inner-IF block…
END — End of outer-IF block…

COMMIT TRANSACTION;
END TRY

BEGIN CATCH
— Test whether the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
PRINT
N’The transaction is in an uncommittable state. ‘ +
‘Rolling back transaction.’
ROLLBACK TRANSACTION;
END;
— Test whether the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
PRINT
N’The transaction is committable. ‘ +
‘Committing transaction.’
COMMIT TRANSACTION;
END;

DECLARE @ErrorMessage [nvarchar](4000);
DECLARE @ErrorSeverity [int];
DECLARE @ErrorState [int];

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();

— RAISERROR inside the CATCH block to return error
— information about the original error that caused
— execution to jump to the CATCH block.
RAISERROR (@ErrorMessage, — Message text.
@ErrorSeverity, — Severity.
@ErrorState ); — State.
END CATCH
END

GO

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
1613
SQL Server Enhancements for Developers: @SlideShare https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/sql-server-technology-enhancements-developers-2008-20122014-slideshare/ Thu, 04 Feb 2016 08:02:39 +0000 https://www.wylieblanchard.com/?p=1501 SQL Server Technology Enhancements for Developers – 2008 to 2012/2014 @SlideShare Your team is planning to upgrade from your SQL Server 2008 environment. Learn what’s new in SQL 2012/2014. Which features and enhancements are really important to the work life of a SQL Server Developer. In this presentation we’ll explore SQL Server 2012/2014 new possibilities, […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
Presence Health Partners - SQL Server Technology Enhancements for Developers - Wylie Blanchard

SQL Server Technology Enhancements for Developers – 2008 to 2012/2014 @SlideShare

Your team is planning to upgrade from your SQL Server 2008 environment. Learn what’s new in SQL 2012/2014. Which features and enhancements are really important to the work life of a SQL Server Developer.

In this presentation we’ll explore SQL Server 2012/2014 new possibilities, showing you how to use new T-SQL functions, features and enhancements that are only available in SQL Server 2012/2014.


SQL Server Technology Enhancements for Developers – 2008 to 2012/2014

  1. SQL Server Technology Enhancements for Developers Upgrade from SQL Server 2008 to 2012/2014 Wylie Blanchard SQL Server Consultant
  2. Presentation Summary Your team is planning to upgrade from your MS SQL Server 2008 environment to a newer platform. Learn what’s new in MS SQL Server 2012/2014. Which features and enhancements are really important to the work life of a SQL Server Developer. In this presentation we’ll explore SQL Server 2012/2014 new possibilities, showing you how to use new T-SQL functions, features and enhancements that are only available in SQL Server 2012/2014.
  3. Enhancements – SQL Server 2012/(2014) T-SQL Functions – T-SQL Analytic Functions (FIRST_VALUE, LAST_VALUE, LEAD, LAG) – T-SQL String Functions (FORMAT, CONCAT ) – T-SQL Expression (COALESCE – not new) SSMS Engine – FileTables – Query Breakpoints enhancements – Sequence Numbers Objects – Contained databases – In-memory OLTP (2014)
  4. T-SQL Analytic Functions T-SQL Functions FIRST_VALUE LAST_VALUE LEAD LAG
  5. FIRST_VALUE / LAST_VALUE Returns the first and last value in a list Get info from result set without using self-joins, derived tables, etc Syntax: FIRST_VALUE ( [scalar_expression ] ) OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] ) Syntax: LAST_VALUE ( [scalar_expression ) OVER ( [ partition_by_clause ] order_by_clause rows_range_clause )
  6. FIRST_VALUE / LAST_VALUE – Demo /** show first value in preceding rows for list **/ USE AdventureWorks2012 GO SELECT s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty, FIRST_VALUE(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID) FstValue, LAST_VALUE(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID) LstValue FROM Sales.SalesOrderDetail s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty GO
  7. FIRST_VALUE / LAST_VALUE – Demo (cont) /** show first value in preceding rows and current value for list sectioned by value **/ USE AdventureWorks2012 GO SELECT s.SalesOrderID,s.SalesOrderDetailID, FIRST_VALUE(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) FstValue, LAST_VALUE(SalesOrderDetailID) OVER (PARTITION BY SalesOrderID ORDER BY SalesOrderDetailID) LstValue FROM Sales.SalesOrderDetail s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty GO
  8. LEAD / LAG Get data from subsequent (LEAD) and previous (LAG) row in same result set Syntax: LAG (scalar_expression [,offset] [,default]) OVER ( [ partition_by_clause ] order_by_clause ) Syntax: LAST_VALUE ( [scalar_expression ) OVER ( [ partition_by_clause ] order_by_clause rows_range_clause )
  9. LEAD and LAG – Demo /** get data from subsequent and previous row **/ USE AdventureWorks2012 GO SELECT s.SalesOrderID,s.SalesOrderDetailID, LEAD(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID ) LeadValue, LAG(SalesOrderDetailID) OVER (ORDER BY SalesOrderDetailID ) LagValue FROM Sales.SalesOrderDetail s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty GO
  10. LEAD / LAG – Demo (cont) /** get data from subsequent and previous row offset by 3 **/ USE AdventureWorks2012 GO SELECT s.SalesOrderID,s.SalesOrderDetailID, LEAD(SalesOrderDetailID,3) OVER (ORDER BY SalesOrderDetailID ) LeadValue, LAG(SalesOrderDetailID,3) OVER (ORDER BY SalesOrderDetailID ) LagValue FROM Sales.SalesOrderDetail s WHERE SalesOrderID IN (43670, 43669, 43667, 43663) ORDER BY s.SalesOrderID,s.SalesOrderDetailID,s.OrderQty GO
  11. T-SQL String Functions T-SQL Functions FORMAT CONCAT
  12. FORMAT Format strings Format dates Format currency – and more Syntax: FORMAT(value, format, [culture]) – Value is the thing to be formatted – Format specifies how we want it to look – Optional Culture specifies the specific language/locale used for formatting. Easier than CONVERT
  13. Formatting Types A valid .NET Framework format string C = Currency D = Date X = hexadecimal
  14. FORMAT – Culture The culture argument is not provided, then the language of the current session is used – Server default – SET LANGUAGE Examples – En-us, fr-fr, de-de, jp-jp
  15. FORMAT – Demo /** old way **/ DECLARE @RevenueA MONEY = 314159.26 SELECT ‘$’ + CONVERT(VARCHAR(32),@RevenueA,1); /** now with format **/ DECLARE @RevenueB MONEY = 314159.26 SELECT FORMAT(@RevenueB,’C’); /** other examples **/ SELECT FORMAT(getdate(), ‘d’); SELECT FORMAT(1234, ‘X’);
  16. FORMAT – Demo (cont) /** custom format values **/ SELECT FORMAT(getdate(), ‘MMMM dd, yyyy (dddd)’); /** format using the culture parameter **/ DECLARE @Revenue MONEY = 314159.26 SELECT FORMAT(@Revenue,’c’,’en-us’) as English; SELECT FORMAT(@Revenue,’c’,’fr-fr’) as French; SELECT FORMAT(@Revenue,’c’,’de-de’) as German; SELECT FORMAT(@Revenue,’c’,’ja-JP’) as Japanese;
  17. CONCAT Concatenates data Easier than using + because all types are cast to strings Syntax: CONCAT ( string1, string2 [, stringN ] ) Output is a string, input is more than one string. Forces conversion to string – PRINT ‘Current Time ‘ + GETDATE() – PRINT CONCAT(‘Current Time ‘, GETDATE())
  18. CONCAT – Demo /** concat in tsql 2012 **/ SELECT CONCAT(1, ‘ two ‘, 3.0, ‘ four’); /** another example **/ SELECT ‘uniqueidentifier = ‘ + NEWID(); — fails SELECT CONCAT(‘uniqueidentifier = ‘, NEWID()); /** print concat trick **/ PRINT ‘Time ‘ + GETDATE(); — fails PRINT ‘Time ‘ + CAST(GETDATE() AS VARCHAR(30)); PRINT CONCAT(‘Time ‘, GETDATE());
  19. T-SQL Expression COALESCE COALESCE (not new) – Introduced with SQL Server 2005 – Not new but it is a function that should be in every developer’s tool belt COALESCE Description – Returns the first non-null expression among its arguments – If all arguments are NULL, COALESCE returns NULL Syntax: COALESCE ( expression [ ,…n ] )
  20. COALESCE – Demo /** select first non null value – returns current date **/ SELECT COALESCE(NULL, NULL, NULL, GETDATE()) /** easily change column list into comma separated values **/ USE AdventureWorks2012 GO DECLARE @columnlist VARCHAR(MAX) SELECT @columnlist = COALESCE(@columnlist+’,’ , ”) + Name FROM Production.Product SELECT @columnlist GO
  21. COALESCE – Demo (cont) /** create dynamic where clause to pass parameters **/ USE AdventureWorks2012 GO CREATE PROCEDURE usp.SearchPersons @FirstName varchar(20), @LastName varchar(20) AS SELECT BusinessEntityID, FirstName, LastName FROM Person.Person WHERE FirstName = COALESCE(@FirstName, FirstName) AND LastName = COALESCE(@LastName, LastName) GO
  22. FileTable SSMS Engine
  23. wait – let’s talk about FILESTREAM FILESTREAM (not new) – Introduced with SQL Server 2008 Used to store data in file system Similar to storing blob data in varbinary(max) column Useful when data objects are too large for varbinar(max) datatype Better performance for large data objects – use system cache instead of sql server cache
  24. FileTables Significantly enhances FILESTREAM capabilities – Store files and documents in special tables called FileTables You can access data, in file system, using T-SQL Applications can access data directly through filesystem – No need to change application logic Use when dealing with data objects too large for varbinar(max) datatype Use when integrating with non transactional applications (middle tier applications)
  25. FileTables Demo Steps: 1. Enable filestream at instance level 2. Create file stream database 3. Create file table 4. Query the file table
  26. Query Breakpoints enhancements SQL Server 2008 allows – create breakpoint – delete breakpoint – disable breakpoint SQL Server 2012 adds – Conditions – Hit Counts (pause when cycle (x) times) – Filter – When Hit (do this) Useful to watch the action of parameters
  27. Query Breakpoints enhancements SSMS Engine
  28. Query Breakpoints enhancements (cont) Conditions – evaluates expression – Useful for tracking parameter scenarios – Ex.: @IntCounter = 5 Hit Counts – track process cycles – Useful to pause at loop points – Ex.: pause when Breakpoint reached (x) times Filter – searches for active specified computers, operating system processes, and threads – Useful for trouble shooting applications – Ex.: ProcessID = 123 When Hit – (do this) – Useful when action is needed once a condition is met
  29. Query Breakpoints enhancements – Demo /** Query Breakpoints demo **/ Declare @IntCounter INT = 1 WHILE( @IntCounter <= 100) BEGIN PRINT @IntCounter –press F9 to create breakpoint and then right click red circle for options SET @IntCounter = @IntCounter + 1 end
  30. Sequence Objects SSMS Engine
  31. SEQUENCE objects CREATE SEQUENCE – Automatically generates numbers Database object that is an alternative to IDENTITY column – found and saved in the database Programmability folder Can be used to get the next sequence of numbers without create a table Example: CREATE SEQUENCE EmployeeSeq AS tinyint START WITH 0 INCREMENT BY 5; GO
  32. Sequence Objects vs Identity column SEQUENCE Object IDENTITY column Table independent Yes No Obtain the new value in your application before using it Yes No Generate new values in an UPDATE statement Yes No Obtain a whole range of new sequence values in one effort Yes No Define minimum and maximum values Yes No
  33. SEQUENCE objects – Demo /** create sequence with max value **/ USE FileStreamDB CREATE SEQUENCE EmployeeSeqToError AS tinyint START WITH 0 INCREMENT BY 5 MAXVALUE 100; GO
  34. SEQUENCE objects – Demo (cont) /** create sequence with max and min value and reseed/recycle **/ USE FileStreamDB CREATE SEQUENCE EmployeeSeqCycle AS tinyint START WITH 1 INCREMENT BY 5 MINVALUE 1 MAXVALUE 100 CYCLE; GO
  35. Contained Databases SSMS Engine
  36. Contained Databases A database that is independent from the SQL Server instance Benefits User authentication can be performed by the database – reduces the databases dependency on the logins of the instance of SQL Server Easily move a database from one instance of SQL Server to another – Metadata maintained in actual database instead of the master database Give db owner more control over database, without giving the db owner sysadmin permission – Errors related to missing users and orphan users are no longer an issue with contained databases
  37. Contained Databases (cont) Disadvantages DB Owner can create contained db users without the permission of a DBA – can lead to security issues & data theft threat Can’t use replication, change data capture, change tracking, numbered procedures, schema-bound objects that depend on built-in functions with collation changes A user confined to the contained database may be able to access other databases on the Database Engine – if the other databases have enabled the guest account
  38. Contained Databases – Demo Steps: 1. Enable database at the server/instance level 2. Enable containment at the database level 3. Create a contained user 4. Test connectivity
  39. Contained Databases – Demo (cont) /** enable database containment on server/instance **/ sp_configure ‘show advanced options’, 1 GO RECONFIGURE WITH OVERRIDE GO sp_configure ‘contained database authentication’, 1 GO RECONFIGURE WITH OVERRIDE GO sp_configure ‘show advanced options’, 0 GO RECONFIGURE WITH OVERRIDE GO
  40. Contained Databases – Demo (cont) /** enable contained database on database **/ USE [master] GO ALTER DATABASE [FileStreamDB] SET CONTAINMENT = PARTIAL WITH NO_WAIT GO /** create a contained user **/ USE [FileStreamDB] GO CREATE USER [MyContainedUser] WITH PASSWORD=N’!LPPeople!’, DEFAULT_SCHEMA=[dbo] GO /** test connectivity **/
  41. Contained Databases – Demo (cont) Test Connectivity – Close and reopen SSMS – Click “Options” once the login screen appears – Select ‘Database Engine’ for “Server type” – Specify the instance that hosts the database for “Server Name” – Enter the user login credentials that were created (Do not click Connect) – Navigate to the “Connection Properties” tab – Specify the name of the contained database in the “Connect to Database” box – Click “Connect”
  42. 42
  43. In-memory OLTP (2014) SSMS Engine
  44. In-memory OLTP New technology released with SQL Server 2014 database engine Memory Optimized Tables – Tables using the new data structures Allow highly used tables to live in memory – Remain in memory forever without losing out a single record Designed to significantly reduce blocking and locks High Performance response than disk tables due to data living in memory
  45. In-memory OLTP – Demo Steps: Create Database Which Creates A File Group Containing Memory_Optimized_Data Create two different tables 1) Regular table and 2) Memory Optimized table Create two stored procedures 1) Regular SP and 2) Natively Compiled SP Compare the performance of two SPs
  46. In-memory OLTP – Demo (cont) /** Create A Table With Setting Memory_Optimized Set To Enabled **/ USE InMemory GO /** create a simple table **/ CREATE TABLE DummyTable (ID INT NOT NULL PRIMARY KEY, Name VARCHAR(100) NOT NULL) GO /** create a memory optimized table **/ CREATE TABLE DummyTable_Mem (ID INT NOT NULL, Name VARCHAR(100) NOT NULL CONSTRAINT ID_Clust_DummyTable_Mem PRIMARY KEY NONCLUSTERED HASH (ID) WITH (BUCKET_COUNT=1000000)) WITH (MEMORY_OPTIMIZED=ON) GO
  47. In-memory OLTP – Demo (cont) /** Create A Stored Procedure Which Is Natively Compiled**/ /** simple table to insert 100,000 rows **/ CREATE PROCEDURE Simple_Insert_test AS BEGIN SET NOCOUNT ON DECLARE @counter AS INT = 1 DECLARE @start DATETIME SELECT @start = GETDATE() WHILE (@counter <= 100000) BEGIN INSERT INTO DummyTable VALUES(@counter, ‘WylieBlanchard’) SET @counter = @counter + 1 END SELECT DATEDIFF(SECOND, @start, GETDATE() ) [Simple_Insert in sec] END GO
  48. Other Features Not mentioned in this presentation but are worth researching. Data Quality Services Data Master Services SQL Server Integration Services – SSIS – Undo and Redo Features – SSIS – Project Deployments SQL Server Reporting Services – SSRS Power View – SSRS Data Alerts – PowerPivot (not new) – Google Chrome enhancements (2014) Azure integration enhancements
  49. Other Features Not mentioned in this presentation but are worth researching. • Data Quality Services • Data Master Services • SQL Server Integration Services – SSIS – Undo and Redo Features – SSIS – Project Deployments • SQL Server Reporting Services – SSRS Power View – SSRS Data Alerts – PowerPivot (not new) – Google Chrome enhancements (2014) • Azure integration enhancements
  50. Resources SQL Server Evaluation Downloads: SQL Server 2012: https://www.microsoft.com/en- us/download/details.aspx?id=29066 SQL Server 2014: https://www.microsoft.com/en- us/evalcenter/evaluate-sql-server-2014 AdventureWorks Sample Database Downloads AdventureWorks 2012: http://msftdbprodsamples.codeplex.com/releases/view/55330 AdventureWorks 2014: https://msftdbprodsamples.codeplex.com/releases/view/125550
  51. Questions & Answers

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
1501
Managing OLAP Databases for DBA’s: @Google+ https://wylieblanchardcom-htezbtd3h0emcxe6.eastus2-01.azurewebsites.net/managing-olap-servers-dbas/ Sun, 07 Dec 2014 01:47:06 +0000 https://www.wylieblanchard.com/?p=2393 With the growing demand for Business Intelligence solutions it’s important that DBA learn how to manage these (not so new) analytical engines to ensure that data is efficient and secure. In this session, we’ll review Microsoft’s SQL Server Analysis Servies Multidimensional (OLAP) engine. We’ll review OLAP cube design, security, access permissions and other SSAS functionalty important […]

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>

With the growing demand for Business Intelligence solutions it’s important that DBA learn how to manage these (not so new) analytical engines to ensure that data is efficient and secure. In this session, we’ll review Microsoft’s SQL Server Analysis Servies Multidimensional (OLAP) engine. We’ll review OLAP cube design, security, access permissions and other SSAS functionalty important to a database admin.

Click here to register now

Presented by: Wylie Blanchard

When: Tuesday, December 6th, 2014 8:00 AM

Westwood College
River Oaks Center, 80 River Oaks Dr #111, Calumet City, IL 60409

Speaker Bio:

Wylie Blanchard, MCSE is an IT consultant, SQL Server professional and web strategist who enjoys helping people learn how to use technology as a tool to amplify their professional lives. He has 15+ years of experience in the IT Industry and holds several certifications in SQL and Oracle systems. He is a father of twin-girls, a gadget enthusiast and a self-proclaimed pizza connoisseur. Learn more about Wylie at: www.WylieBlanchard.com

Get more great content at WylieBlanchard.com... Need a great speaker for your next event, contact us to book Wylie Blanchard now.
Learn what clients are saying about his programs....

]]>
2393