DROP TABLE #advopt_old_value
DROP TABLE #comp_old_value
---------------------------------------------------------------
-- Data Collector: Security: Permissions
---------------------------------------------------------------

PRINT ''
PRINT 'Granting permissions to data collector roles...'

GRANT SELECT  ON [dbo].[syscollector_config_store]                                TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_enable_collector]                        TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_disable_collector]                        TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_warehouse_instance_name]            TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_warehouse_database_name]            TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_cache_window]                        TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_set_cache_directory]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_get_warehouse_connection_string]        TO [dc_proxy]
GRANT EXECUTE ON [dbo].[fn_syscollector_highest_incompatible_mdw_version]		TO [dc_admin], [dc_proxy]

GRANT SELECT  ON [dbo].[syscollector_collector_types]                            TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collector_type]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collector_type]                    TO [dc_admin]

GRANT SELECT  ON [dbo].[syscollector_collection_sets]                            TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collection_set]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collection_set]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_update_collection_set]                    TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_start_collection_set]                    TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_stop_collection_set]                    TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_upload_collection_set]                    TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_run_collection_set]                        TO [dc_operator]

GRANT SELECT  ON [dbo].[syscollector_collection_items]                            TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_create_collection_item]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_collection_item]                    TO [dc_admin]
GRANT EXECUTE ON [dbo].[sp_syscollector_update_collection_item]                    TO [dc_operator]

GRANT SELECT  ON [dbo].[syscollector_execution_log]                                TO [dc_operator]
GRANT SELECT  ON [dbo].[syscollector_execution_log_full]                        TO [dc_operator]
GRANT SELECT  ON [dbo].[syscollector_execution_stats]                            TO [dc_operator]

GRANT EXECUTE ON [dbo].[fn_syscollector_find_collection_set_root]                TO [dc_operator]
GRANT SELECT  ON [dbo].[fn_syscollector_get_execution_log_tree]                    TO [dc_operator]
GRANT SELECT  ON [dbo].[fn_syscollector_get_execution_stats]                    TO [dc_operator]
GRANT SELECT  ON [dbo].[fn_syscollector_get_execution_details]                    TO [dc_operator]
GRANT EXECUTE ON [dbo].[sp_syscollector_delete_execution_log_tree]                TO [dc_operator]

GRANT EXECUTE ON [dbo].[sp_syscollector_event_oncollectionbegin]                TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_oncollectionend]                    TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackagebegin]                    TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackageend]                        TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onpackageupdate]                    TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onerror]                            TO [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_event_onstatsupdate]                    TO [dc_proxy]

GRANT EXECUTE ON [dbo].[sp_syscollector_create_tsql_query_collector]            TO [dc_operator], [dc_proxy]
GRANT EXECUTE ON [dbo].[sp_syscollector_get_tsql_query_collector_package_ids]   TO [dc_operator], [dc_proxy]

GRANT EXECUTE ON [dbo].[sp_verify_subsystems]                                   TO [dc_operator]

---------------------------------------------------------------
-- Relational storage for DMF objects
---------------------------------------------------------------

CREATE TABLE #objects_to_drop(
    type nvarchar(128),
    name sysname
)

-- List of shared registered server objects to be deleted from msdb. Note: order is important!
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_verify_shared_server_type]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_update_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_rename_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_update_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_rename_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_move_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_delete_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_move_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_delete_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_add_shared_registered_server]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_sysmanagement_add_shared_server_group]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',              '[dbo].[sysmanagement_shared_registered_servers]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',              '[dbo].[sysmanagement_shared_server_groups]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',         '[dbo].[sysmanagement_delete_shared_server_group_trigger]')

-- List of policy management objects to be deleted from msdb. Note: order is important!
INSERT INTO #objects_to_drop VALUES ('TRIGGER',           '[dbo].[syspolicy_insert_target_set_level_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',           '[dbo].[syspolicy_update_target_set_level_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',           '[dbo].[syspolicy_insert_target_set_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',           '[dbo].[syspolicy_delete_target_set_trigger]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION',        '[dbo].[syspolicy_fn_filter_complete]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION',        '[dbo].[syspolicy_fn_eventing_filter]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_add_target_set_condition_reference]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_update_target_set_condition_reference]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',             '[dbo].[syspolicy_target_set_condition_references]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_add_target_set_level]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_update_target_set_level]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',             '[dbo].[syspolicy_target_set_levels]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_verify_object_set_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_verify_object_set_references]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_add_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_delete_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_update_target_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_add_object_set]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',          '[dbo].[sp_syspolicy_delete_object_set]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',             '[dbo].[syspolicy_target_sets]' )

INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_events_reader]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_dispatch_event]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_delete_policy_execution_history]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_log_policy_execution_detail]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_log_policy_execution_end]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_log_policy_execution_start]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_policy_execution_history_details]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_policy_execution_history]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',    		'[dbo].[syspolicy_update_system_health_state]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_system_health_state]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_delete_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_update_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_add_policy_category_subscription]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_policy_category_subscriptions]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_delete_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_update_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_rename_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_verify_policy_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_add_policy]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_rename_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_update_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_delete_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_add_policy_category]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_verify_policy_category_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_policies]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_create_job]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_delete_job_delete_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_update_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_insert_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_update_job_update_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_insert_job_create_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_instead_delete_policy_trigger]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_policy_categories]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_rename_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_delete_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_update_condition]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_verify_condition_identifiers]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE', 		'[dbo].[sp_syspolicy_add_condition]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',      		'[dbo].[syspolicy_conditions]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',    		'[dbo].[syspolicy_insert_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',    		'[dbo].[syspolicy_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_for_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',   		'[dbo].[syspolicy_after_update_condition_trigger]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',     		'[dbo].[syspolicy_object_sets]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION',  		'[dbo].[syspolicy_fn_get_type_name]' )
INSERT INTO #objects_to_drop VALUES ('INLINE FUNCTION',  		'[dbo].[syspolicy_fn_get_bad_filters]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  		'[dbo].[sp_syspolicy_check_membership]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION',  		'[dbo].[fn_syspolicy_get_ps_command]' )
INSERT INTO #objects_to_drop VALUES ('VIEW',            '[dbo].[syspolicy_configuration]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_configure]' )
INSERT INTO #objects_to_drop VALUES ('FUNCTION',  	    '[dbo].[fn_syspolicy_is_automation_enabled]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_set_config_enabled]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_repair_policy_automation]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_purge_history]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_set_config_history_retention]' )
INSERT INTO #objects_to_drop VALUES ('TRIGGER',  	    '[dbo].[syspolicy_validate_events]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_create_purge_job]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_purge_health_state]' )
INSERT INTO #objects_to_drop VALUES ('PROCEDURE',  	    '[dbo].[sp_syspolicy_set_log_on_success]' )

GO

DECLARE @object_name sysname
DECLARE @object_type nvarchar(128)

DECLARE object_to_drop_cursor CURSOR LOCAL FOR SELECT type, name FROM #objects_to_drop

OPEN object_to_drop_cursor
FETCH object_to_drop_cursor INTO @object_type, @object_name

WHILE @@FETCH_STATUS = 0 
BEGIN
    DECLARE @stmt nvarchar(128)
    DECLARE @object_kind nvarchar(2)

    SET @object_kind = 
        CASE @object_type
            WHEN 'VIEW'       THEN 'V'
            WHEN 'PROCEDURE'  THEN 'P'
            WHEN 'TRIGGER'    THEN 'TR'
            WHEN 'FUNCTION'    THEN 'FN'
            WHEN 'INLINE FUNCTION'    THEN 'IF'
            WHEN 'TABLE TYPE'    THEN 'TT'
            ELSE NULL
        END

    IF @object_kind IS NULL
    BEGIN
        DECLARE @errtxt nvarchar(max)
        SET @errtxt = 'Incorrect object type "' + @object_type + '" for object "' + @object_name + '", check "INSERT INTO #objects_to_drop..." statement'
        RAISERROR(@errtxt, 20, 127) WITH LOG
    END

    IF (OBJECT_ID(@object_name, @object_kind) IS NULL)
        PRINT 'Object "' + @object_name + N'" does not exist, will not drop'
    ELSE
    BEGIN
        IF( @object_type = 'INLINE FUNCTION')
            SET @object_type = 'FUNCTION'
        SET @stmt = N'drop ' + @object_type + N' ' + @object_name
        PRINT 'Executing "' + @stmt + N'"'
        EXECUTE(@stmt)
    END
    FETCH object_to_drop_cursor INTO @object_type, @object_name
END

CLOSE object_to_drop_cursor
DEALLOCATE object_to_drop_cursor
DROP TABLE #objects_to_drop

PRINT 'Done dropping all DMF and Shared Registered Server procedures'
GO


--------------------------------------------------------------
-- This section contains shared registered servers information
--------------------------------------------------------------

IF NOT EXISTS (SELECT * FROM sys.tables where name ='sysmanagement_shared_server_groups_internal')
BEGIN
	PRINT 'Creating table [msdb].[dbo].[sysmanagement_shared_server_groups_internal]...'
	CREATE TABLE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
	(
		server_group_id INT NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED,
		name sysname NOT NULL,
		description NVARCHAR (2048) NOT NULL,
		-- You can only have a registered server of the same type within a group of the same type
		-- So the group needs to have knowledge of its type
		server_type INT NOT NULL,
		-- Explicitly allow NULLs for this column, so we are independent of server configuration
		parent_id INT NULL,
		-- this flag indicates whether the group is a system builtin group
		is_system_object BIT DEFAULT 0,
		-- Make sure each name is unique per parent
		CONSTRAINT [UQ_sysmanagement_unique_group_name_per_parent] UNIQUE(parent_id, name)
	);

    CREATE CLUSTERED    INDEX [IX_sysmanagement_shared_server_groups_clustParentGroupID] ON
                [dbo].[sysmanagement_shared_server_groups_internal] (parent_id);
    CREATE NONCLUSTERED INDEX [IX_sysmanagement_shared_server_groups_name] ON
                [dbo].[sysmanagement_shared_server_groups_internal] (name)

    -- populate with the builtin server groups
    -- Note: server_type_id values must match the ServerType enumeration
    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
    VALUES (N'DatabaseEngineServerGroup', N'Builtin group that contains the DatabaseEngine servers', 0, null, 1);

    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
    VALUES (N'AnalysisServicesServerGroup', N'Builtin group that contains the AnalysisServices servers', 1, null, 1);

    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
    VALUES (N'ReportingServicesServerGroup', N'Builtin group that contains the ReportingServices servers', 2, null, 1);

    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
    VALUES (N'IntegrationServicesServerGroup', N'Builtin group that contains the IntegrationServices servers', 3, null, 1);

    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (name, description, server_type, parent_id, is_system_object)
    VALUES (N'SqlServerCompactEditionServerGroup', N'Builtin group that contains the SqlServerCompactEdition servers', 4, null, 1);

END
ELSE
BEGIN
	UPDATE 
		[msdb].[dbo].[sysmanagement_shared_server_groups_internal]
	SET 
		name = N'SqlServerCompactEditionServerGroup',
		description = N'Builtin group that contains the SqlServerCompactEdition servers'
	WHERE
		name = N'SqlServerEverywhereServerGroup' and
		server_type = 4 and
		is_system_object = 1;
END

GO
PRINT 'Creating trigger [sysmanagement_delete_shared_server_group_trigger]...'
GO
CREATE TRIGGER [sysmanagement_delete_shared_server_group_trigger] on [msdb].[dbo].[sysmanagement_shared_server_groups_internal] 
FOR DELETE
AS
BEGIN
    -- system server groups should not be deleted
    IF EXISTS (SELECT * FROM deleted where is_system_object = 1)
    BEGIN
        RAISERROR (35008, 1, 1)
        ROLLBACK TRANSACTION
    END
END
GO

IF NOT EXISTS ( SELECT * FROM sys.tables WHERE name = 'sysmanagement_shared_registered_servers_internal')
BEGIN
    PRINT 'Creating table [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]...'
    CREATE TABLE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
    (
        server_id INT NOT NULL IDENTITY PRIMARY KEY NONCLUSTERED,
        server_group_id INT FOREIGN KEY REFERENCES [msdb].[dbo].[sysmanagement_shared_server_groups_internal] (server_group_id) ON DELETE CASCADE,
        name sysname NOT NULL,
        server_name sysname NOT NULL,
        description NVARCHAR(2048) NOT NULL,
        -- While the server group has the knowledge of the server type,
        -- you also need the Server Type here, because you can have a root registered server with no parent group
        server_type INT NOT NULL,
        -- Make sure each registered name is unique in each group
        CONSTRAINT [UQ_sysmanagement_unique_server_name_per_group] UNIQUE(server_group_id, name)
    )

    CREATE CLUSTERED    INDEX [IX_sysmanagement_shared_registered_servers_clustGroupID] ON
                [dbo].[sysmanagement_shared_registered_servers_internal] (server_group_id);
    CREATE NONCLUSTERED INDEX [IX_sysmanagement_shared_registered_servers_name] ON
                [dbo].[sysmanagement_shared_registered_servers_internal] (name)
END
GO

PRINT 'Creating view [dbo].[sysmanagement_shared_server_groups]...'
GO
CREATE VIEW [dbo].[sysmanagement_shared_server_groups]
AS
(
    SELECT server_group_id, name, description, server_type, parent_id, is_system_object,
    (select COUNT(*) from [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sgChild where sgChild.parent_id = sg.server_group_id) as num_server_group_children,
    (select COUNT(*) from [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] rsChild where rsChild.server_group_id = sg.server_group_id) as num_registered_server_children
    FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] sg
)
GO

PRINT 'Creating view [dbo].[sysmanagement_shared_registered_servers]...'
GO
CREATE VIEW [dbo].[sysmanagement_shared_registered_servers]
AS
(
    SELECT server_id, server_group_id, name, server_name, description, server_type
    FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
)
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_verify_shared_server_type]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_verify_shared_server_type]
    @server_type INT
AS
BEGIN
    IF (@server_type IS NULL)
    BEGIN
        RAISERROR (35009, -1, -1)
        RETURN(1)
    END
    
    -- 0 --> DatabaseEngineServerGroup, 1 --> AnalysisServicesServerGroup, 2 --> ReportingServicesServerGroup, 3 --> IntegrationServicesServerGroup, 4 --> SqlServerCompactEditionServerGroup
    IF (@server_type < 0 OR @server_type > 4)
    BEGIN
        RAISERROR (35010, -1, -1, @server_type)
        RETURN (1)
    END
    
    RETURN (0)
END
GO


PRINT 'Creating procedure [dbo].[sp_sysmanagement_add_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_add_shared_server_group]
    @name sysname,
    @description NVARCHAR (2048) = N'',
    @parent_id INT,
    @server_type INT,
    @server_group_id INT OUTPUT
AS
BEGIN
    DECLARE @retval INT

    EXECUTE @retval = sp_sysmanagement_verify_shared_server_type @server_type

    IF (@retval <> 0)
        RETURN(1) -- Failure
    
    -- user created server groups should have a valid parent 
    IF( (@parent_id IS NULL) OR 
        (@parent_id NOT IN (SELECT sg.server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups_internal sg)))
    BEGIN
        RAISERROR (35001, -1, -1)
        RETURN (1)
    END

    IF EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal]  sg 
                WHERE @parent_id = sg.server_group_id AND @server_type <> sg.server_type)
    BEGIN
        RAISERROR (35002, -1, -1)
        RETURN (1)
    END    
    
    INSERT INTO [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
        (name, description, parent_id, server_type)
    VALUES
        (
        @name, 
        @description, 
        @parent_id, 
        @server_type
        )

    SELECT @server_group_id = SCOPE_IDENTITY()
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_add_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_add_shared_registered_server]
    @name sysname,
    @server_group_id INT,
    @server_name sysname,
    @description NVARCHAR(2048) = N'',
    @server_type INT,
    @server_id INT OUTPUT
AS
BEGIN
    DECLARE @retval INT

    EXECUTE @retval = sp_sysmanagement_verify_shared_server_type @server_type

    IF (@retval <> 0)
        RETURN(1) -- Failure
    
    IF( (@server_group_id IS NULL) OR 
        (@server_group_id NOT IN (SELECT sg.server_group_id FROM msdb.dbo.sysmanagement_shared_server_groups_internal sg)))
    BEGIN
        RAISERROR (35001, -1, -1)
        RETURN (1)
    END

    IF EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal]  sg 
                WHERE @server_group_id = sg.server_group_id AND @server_type <> sg.server_type)
    BEGIN
        RAISERROR (35002, -1, -1)
        RETURN (1)
    END    

    IF (@server_name IS NULL)
    BEGIN
        RAISERROR(14618, -1, 1, '@server_name')
        RETURN(1)   
    END

    set @server_name = LTRIM(@server_name)
    set @server_name = RTRIM(@server_name)

    -- Disallow relative names
    IF ('.' = @server_name) OR
        (1 = CHARINDEX(N'.\', @server_name)) OR
        (1 = CHARINDEX(N'LOCALHOST\', UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))) OR
        (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = 'LOCALHOST') OR
        (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
    BEGIN
        RAISERROR (35011, -1, -1)
        RETURN (1)
    END

    IF (UPPER(@@SERVERNAME collate SQL_Latin1_General_CP1_CS_AS) = UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))
    BEGIN
        RAISERROR (35012, -1, -1)
        RETURN (1)
    END

    INSERT INTO [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
        (server_group_id, name, server_name, description, server_type)
    VALUES
        (@server_group_id, @name, @server_name, @description, @server_type)
        
    SELECT @server_id = SCOPE_IDENTITY()
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_delete_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_delete_shared_server_group]
    @server_group_id INT
AS
BEGIN
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
    BEGIN
        RAISERROR (35004, -1, -1)
        RETURN(1)
    END;

    WITH ChildGroups (parent_id, server_group_id, name, server_type, server_level)
    AS
    (
        -- Anchor
        SELECT g.parent_id, g.server_group_id, g.name, g.server_type, 0 AS server_level
        FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS g
        WHERE g.server_group_id = @server_group_id
        UNION ALL
        -- Recursive definition
        SELECT r.parent_id, r.server_group_id, r.name, r.server_type, server_level + 1
        FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS r
        INNER JOIN ChildGroups AS children ON r.parent_id = children.server_group_id
    )
    -- Execute CTE to delete the hierarchy of server groups
    DELETE FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
        FROM ChildGroups children
        JOIN [msdb].[dbo].[sysmanagement_shared_server_groups_internal] ServerGroups
            ON children.server_group_id = ServerGroups.server_group_id
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_delete_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_delete_shared_registered_server]
    @server_id INT
AS
BEGIN
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
    BEGIN
        RAISERROR (35007, -1, -1)
        RETURN(1)
    END
    
    DELETE FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
    WHERE
            server_id = @server_id
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_move_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_move_shared_server_group]
    @server_group_id INT,
    @new_parent_id INT
AS
BEGIN
    IF (@new_parent_id IS NULL) OR 
        NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
    BEGIN
        RAISERROR (35001, -1, -1)
        RETURN(1)
    END

    IF (@new_parent_id IS NOT NULL)
        AND ((SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
                <>
             (SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id))
    BEGIN
        RAISERROR (35002, -1, -1)
        RETURN(1)
    END

    DECLARE @DeletedGroups TABLE
    (
        server_group_id int
    );

    -- Check if the destination group you're moving to isn't already a descendant of the current group
    WITH ChildGroups (parent_id, server_group_id, server_level)
    AS
    (
        -- Anchor
        SELECT g.parent_id, g.server_group_id, 0 AS server_level
        FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS g
        WHERE g.server_group_id = @server_group_id
        UNION ALL
        -- Recursive definition
        SELECT r.parent_id, r.server_group_id, server_level + 1
        FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] AS r
        INNER JOIN ChildGroups AS children ON r.parent_id = children.server_group_id
    )
    -- Execute CTE
    INSERT INTO @DeletedGroups
    SELECT server_group_id FROM ChildGroups

    IF (SELECT COUNT(*) FROM @DeletedGroups WHERE server_group_id = @new_parent_id) > 0
    BEGIN
        RAISERROR (35003, -1, -1)
        RETURN(1)
    END
    
    UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
        SET parent_id = @new_parent_id
    WHERE
        server_group_id = @server_group_id
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_move_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_move_shared_registered_server]
    @server_id INT,
    @new_parent_id INT
AS
BEGIN
    IF (@server_id IS NULL)
    BEGIN
        RAISERROR (35006, -1, -1)
        RETURN(1)
    END
    
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
    BEGIN
        RAISERROR (35007, -1, -1)
        RETURN(1)
    END
    
    IF (@new_parent_id IS NULL) OR 
        NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
    BEGIN
        RAISERROR (35001, -1, -1)
        RETURN(1)
    END

    IF (@new_parent_id IS NOT NULL)
        AND ((SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @new_parent_id)
                <>
             (SELECT server_type FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id))
    BEGIN
        RAISERROR (35002, -1, -1)
        RETURN(1)
    END
    
    UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
        SET server_group_id = @new_parent_id
    WHERE
        server_id = @server_id
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_update_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_update_shared_server_group]
    @server_group_id INT,
    @description NVARCHAR (2048) = NULL
AS
BEGIN
    IF (@server_group_id IS NULL)
    BEGIN
        RAISERROR (35005, -1, -1)
        RETURN(1)
    END

    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
    BEGIN
        RAISERROR (35004, -1, -1)
        RETURN(1)
    END

    UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
        SET description = ISNULL(@description, description)
    WHERE
        server_group_id = @server_group_id
    
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_update_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_update_shared_registered_server]
    @server_id INT,
    @server_name sysname = NULL,
    @description NVARCHAR(2048) = NULL
AS
BEGIN
    IF (@server_id IS NULL)
    BEGIN
        RAISERROR (35006, -1, -1)
        RETURN(1)
    END
    
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
    BEGIN
        RAISERROR (35007, -1, -1)
        RETURN(1)
    END

    IF (@server_name IS NULL)
    BEGIN
        SET @server_name = (select server_name FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
    END

    set @server_name = LTRIM(@server_name)
    set @server_name = RTRIM(@server_name)

    -- Disallow relative names
    IF ('.' = @server_name) OR
        (1 = CHARINDEX(N'.\', @server_name)) OR
        (1 = CHARINDEX(N'LOCALHOST\', UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))) OR
        (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = 'LOCALHOST') OR
        (UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS) = '(LOCAL)')
    BEGIN
        RAISERROR (35011, -1, -1)
        RETURN (1)
    END

    IF (UPPER(@@SERVERNAME collate SQL_Latin1_General_CP1_CS_AS) = UPPER(@server_name collate SQL_Latin1_General_CP1_CS_AS))
    BEGIN
        RAISERROR (35012, -1, -1)
        RETURN (1)
    END

    UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
        SET server_name = ISNULL(@server_name, server_name),
            description = ISNULL(@description, description)
    WHERE
        server_id = @server_id
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_sysmanagement_rename_shared_server_group]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_rename_shared_server_group]
    @server_group_id INT,
    @new_name sysname
AS
BEGIN
    IF (@server_group_id IS NULL)
    BEGIN
        RAISERROR (35006, -1, -1)
        RETURN(1)
    END
    
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_server_groups_internal] WHERE server_group_id = @server_group_id)
    BEGIN
        RAISERROR (35007, -1, -1)
        RETURN(1)
    END
    
    IF (@new_name IS NULL or LEN(@new_name) = 0)
    BEGIN
      RAISERROR(21263, -1, -1, '@new_name')
      RETURN(1) -- Failure
    END

    UPDATE [msdb].[dbo].[sysmanagement_shared_server_groups_internal]
        SET name = @new_name
    WHERE
        server_group_id = @server_group_id

    RETURN (0)
END
GO


PRINT 'Creating procedure [dbo].[sp_sysmanagement_rename_shared_registered_server]...'
GO
CREATE PROCEDURE [dbo].[sp_sysmanagement_rename_shared_registered_server]
    @server_id INT,
    @new_name sysname
AS
BEGIN
    IF (@server_id IS NULL)
    BEGIN
        RAISERROR (35006, -1, -1)
        RETURN(1)
    END
    
    IF NOT EXISTS (SELECT * FROM [msdb].[dbo].[sysmanagement_shared_registered_servers_internal] WHERE server_id = @server_id)
    BEGIN
        RAISERROR (35007, -1, -1)
        RETURN(1)
    END
    
    IF (@new_name IS NULL or LEN(@new_name) = 0)
    BEGIN
      RAISERROR(21263, -1, -1, '@new_name')
      RETURN(1) -- Failure
    END

    UPDATE [msdb].[dbo].[sysmanagement_shared_registered_servers_internal]
        SET name = @new_name
    WHERE
        server_id = @server_id

    RETURN (0)
END
GO


-----------------------------------------------------------
-- This section contains facet information
-----------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_management_facets')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_management_facets]...';
    CREATE TABLE [dbo].[syspolicy_management_facets] (
        management_facet_id int NOT NULL IDENTITY PRIMARY KEY,
        name nvarchar(MAX) NOT NULL,    -- this is the name of the management facet
        execution_mode int NOT NULL
    );

END

GO

-- Create a temp table for the facets that are supposed to ship out of the box
-- Later the script will use the temp table to add any new facets to the syspolicy_management_facets table
declare @temp_syspolicy_management_facets TABLE(
    name nvarchar(MAX) NOT NULL,    -- this is the name of the management facet
    execution_mode int NOT NULL);
                
-- populate the temp table with facets shipping out of the box
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ApplicationRole', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('AsymmetricKey', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Audit', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BackupDevice', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BrokerPriority', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('BrokerService', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Certificate', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Credential', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('CryptographicProvider', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Database', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseAuditSpecification', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseDdlTrigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DatabaseRole', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('DataFile', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Default', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Endpoint', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FileGroup', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextCatalog', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextIndex', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('FullTextStopList', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseMaintenanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseOptions', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabasePerformanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IDatabaseSecurityFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ILoginOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IMultipartNameFacet', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('INameFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ITableOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IUserOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IViewOptions', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Index', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerAuditFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerConfigurationFacet', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerInformation', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerPerformanceFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSecurityFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSetupFacet', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('IServerSettings', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaConfigurationForAnalysisServer', 0);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaConfigurationForReportingServices', 0);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ISurfaceAreaFacet', 6);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('LinkedServer', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('LogFile', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Login', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('MessageType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PartitionFunction', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PartitionScheme', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('PlanGuide', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('RemoteServiceBinding', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ResourceGovernor', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ResourcePool', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Rule', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Schema', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Server', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServerAuditSpecification', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServerDdlTrigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceContract', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceQueue', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('ServiceRoute', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Statistic', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('StoredProcedure', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('SymmetricKey', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Synonym', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Table', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('Trigger', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('User', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedAggregate', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedDataType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedFunction', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedTableType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('UserDefinedType', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('View', 4);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('WorkloadGroup', 7);
INSERT @temp_syspolicy_management_facets (name, execution_mode) VALUES ('XmlSchemaCollection', 4);

-- Facets can be updated and inserted, however deleting a facet is dangerous because of references from conditions

-- Update the modes on the facets
UPDATE facets
SET facets.execution_mode = tempFacets.execution_mode 
FROM @temp_syspolicy_management_facets tempFacets, [msdb].[dbo].[syspolicy_management_facets] facets
WHERE tempFacets.name = facets.name AND tempFacets.execution_mode <> facets.execution_mode;

-- Now populate the syspolicy_management_facets table with the facets that are missing in the table
INSERT [msdb].[dbo].[syspolicy_management_facets] (name, execution_mode)
    SELECT tempFacets.name, tempFacets.execution_mode
    FROM @temp_syspolicy_management_facets tempFacets
    WHERE tempFacets.name NOT IN (SELECT distinct facets.name FROM [msdb].[dbo].[syspolicy_management_facets] facets)
    


GO

---------------------------------------------------------------
-- Relational storage for policy objects
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_facet_events')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_facet_events]...';
    CREATE TABLE [dbo].[syspolicy_facet_events] (
        management_facet_id int NOT NULL REFERENCES [dbo].[syspolicy_management_facets],
        event_name sysname NOT NULL,                -- this is the name of the event
        target_type sysname NOT NULL,                -- type of the target (TABLE, PROCEDURE etc.)
        target_type_alias sysname NOT NULL);        -- this is an alias for the type of the target
                                                    -- it can happen that the same target type 
                                                    -- shows up as different strings in the event

    CREATE CLUSTERED INDEX [IX_facet_events_target_type_alias] ON 
        [dbo].[syspolicy_facet_events] (target_type_alias);
    CREATE UNIQUE INDEX [UX_facet_events] ON 
        [dbo].[syspolicy_facet_events] (management_facet_id, event_name, target_type, target_type_alias);
END
GO
-- The facet events are unique to an installation, thus delete what is there and then insert the new events
-- This technique will work for both a new install and an upgrade.
DELETE FROM [msdb].[dbo].[syspolicy_facet_events]

-- this is a pseudo event, so we're inserting it before the
-- consistency check is in place
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'SAC_ENDPOINT_CHANGE',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ISurfaceAreaFacet'
 

GO
CREATE TRIGGER [syspolicy_validate_events] on [dbo].[syspolicy_facet_events]
AFTER INSERT, UPDATE
AS
BEGIN
    -- make sure that caller is dbo and all events inserted are real events.
    IF  (USER_ID() != 1) OR
        EXISTS (SELECT event_name FROM inserted 
                    WHERE event_name NOT IN(SELECT type_name from sys.event_notification_event_types))
    BEGIN
        RAISERROR(N'Unknown event name inserted into [dbo].[syspolicy_facet_events]', 1,1)
        ROLLBACK TRANSACTION
    END
END
GO

-- Insert the facet events               
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_APPLICATION_ROLE',N'APPLICATION ROLE',N'APPLICATION ROLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ApplicationRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_APPLICATION_ROLE',N'APPLICATION ROLE',N'APPLICATION ROLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ApplicationRole'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_ASYMMETRIC_KEY',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'AsymmetricKey'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_ASYMMETRIC_KEY',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'AsymmetricKey'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'ASYMMETRICKEY',N'ASYMMETRIC KEY'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'AsymmetricKey'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_ROLE',N'ROLE',N'ROLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'DatabaseRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_ROLE',N'ROLE',N'ROLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'DatabaseRole'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'ROLE',N'ROLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'DatabaseRole'

INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_ENDPOINT',N'ENDPOINT',N'ENDPOINT'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Endpoint'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_ENDPOINT',N'ENDPOINT',N'ENDPOINT'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Endpoint'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_SERVER',N'ENDPOINT',N'ENDPOINT'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Endpoint'
   
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_DATABASE',N'DATABASE',N'DATABASE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IDatabaseOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_DATABASE',N'DATABASE',N'DATABASE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IDatabaseOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'DATABASE',N'DATABASE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IDatabaseOptions'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_FUNCTION',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_FUNCTION',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_SYNONYM',N'SYNONYM',N'SYNONYM'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_TABLE',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_TABLE',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_TYPE',N'TYPE',N'TYPE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'TYPE',N'TYPE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_VIEW',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_VIEW',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_XML_SCHEMA_COLLECTION',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_XML_SCHEMA_COLLECTION',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'SYNONYM',N'SYNONYM'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'TYPE',N'TYPE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'XMLSCHEMACOLLECTION',N'XMLSCHEMACOLLECTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IMultipartNameFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'AUDIT_SERVER_OPERATION_EVENT',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IServerConfigurationFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'AUDIT_SERVER_OPERATION_EVENT',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ISurfaceAreaFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_ENDPOINT',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ISurfaceAreaFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_ENDPOINT',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ISurfaceAreaFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'DROP_ENDPOINT',N'SERVER',N'SERVER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ISurfaceAreaFacet'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_LOGIN',N'LOGIN',N'LOGIN'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ILoginOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_LOGIN',N'LOGIN',N'LOGIN'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ILoginOptions'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_RESOURCE_POOL',N'RESOURCEPOOL',N'RESOURCE POOL'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ResourcePool'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_RESOURCE_POOL',N'RESOURCEPOOL',N'RESOURCE POOL'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ResourcePool'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'SCHEMA',N'SCHEMA'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Schema'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_SCHEMA',N'SCHEMA',N'SCHEMA'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Schema'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'SCHEMA',N'SCHEMA'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'Schema'
  
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_PROCEDURE',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'StoredProcedure'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'PROCEDURE',N'PROCEDURE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'StoredProcedure'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_TABLE',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_TABLE',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ITableOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'TABLE',N'TABLE'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'ITableOptions'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_USER',N'USER',N'ASYMMETRIC KEY USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_USER',N'USER',N'CERTIFICATE USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_USER',N'USER',N'GROUP USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_USER',N'USER',N'SQL USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_USER',N'USER',N'WINDOWS USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_USER',N'USER',N'ASYMMETRIC KEY USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_USER',N'USER',N'CERTIFICATE USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_USER',N'USER',N'GROUP USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_USER',N'USER',N'SQL USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_USER',N'USER',N'WINDOWS USER'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IUserOptions'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_FUNCTION',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_FUNCTION',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'UserDefinedFunction'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'FUNCTION',N'FUNCTION'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'UserDefinedFunction'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_VIEW',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_VIEW',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'RENAME',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_AUTHORIZATION_DATABASE',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IViewOptions'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_SCHEMA',N'VIEW',N'VIEW'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'IViewOptions'
 
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'CREATE_WORKLOAD_GROUP',N'WORKLOADGROUP',N'WORKLOAD GROUP'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'WorkloadGroup'
INSERT [msdb].[dbo].[syspolicy_facet_events] (management_facet_id,event_name,target_type,target_type_alias) 
 SELECT management_facet_id,N'ALTER_WORKLOAD_GROUP',N'WORKLOADGROUP',N'WORKLOAD GROUP'
 FROM [msdb].[dbo].[syspolicy_management_facets]
 WHERE name = 'WorkloadGroup'

        
GO
---------------------------------------------------------------
-- Condition object
---------------------------------------------------------------

IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_conditions_internal')
BEGIN
PRINT 'Creating table [dbo].[syspolicy_conditions_internal]...'
CREATE TABLE [dbo].[syspolicy_conditions_internal] (
    condition_id int IDENTITY(1,1),
    name sysname NOT NULL,
    date_created datetime default GETDATE(),
    description nvarchar(max) NOT NULL default (''),
    created_by sysname NOT NULL default SUSER_SNAME(),
    modified_by sysname NULL,
    date_modified datetime NULL,
    facet_id int,
    expression nvarchar(max),
    is_name_condition smallint default (0),
    obj_name sysname NULL,
    CONSTRAINT [PK_syspolicy_conditions] PRIMARY KEY CLUSTERED (condition_id ASC),
    CONSTRAINT [UQ_syspolicy_conditions_name] UNIQUE(name)
    );
ALTER TABLE [dbo].[syspolicy_conditions_internal] 
    ADD CONSTRAINT [FK_syspolicy_conditions_internal_facet] FOREIGN KEY(facet_id)
    REFERENCES [dbo].[syspolicy_management_facets] (management_facet_id);
END
GO

PRINT 'Creating view [dbo].[syspolicy_conditions]...'
GO
CREATE VIEW [dbo].[syspolicy_conditions]
AS
    SELECT
        c.condition_id, c.name, c.date_created, c.description, c.created_by, 
        c.modified_by, c.date_modified, c.is_name_condition, mf.name AS facet, c.expression, c.obj_name 
    FROM [dbo].[syspolicy_conditions_internal] c 
    LEFT OUTER JOIN [dbo].[syspolicy_management_facets] mf ON c.facet_id = mf.management_facet_id
GO

CREATE PROCEDURE [dbo].[sp_syspolicy_check_membership]
@role sysname,
@raiserror bit = 1
AS
BEGIN
	-- make sure that the caller is dbo or @role
	IF ( IS_MEMBER(@role) != 1 AND USER_ID() != 1)
	BEGIN
		IF (@raiserror = 1)
		BEGIN
			RAISERROR(15003, -1, -1, @role);
		END
		RETURN 15003;
	END
	
	RETURN 0;
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_condition] 
@name sysname,
@description nvarchar(max) = N'',
@facet nvarchar(max),
@expression nvarchar(max),
@is_name_condition smallint = 0,
@obj_name sysname = NULL,
@condition_id int = NULL OUTPUT 
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT
	DECLARE @facet_id            INT
	DECLARE @null_column	sysname
	
	SET @null_column = NULL

    IF (@name IS NULL OR @name = N'')
        SET @null_column = '@name'
    ELSE IF( @description IS NULL)
        SET @null_column = '@description'
    ELSE IF( @facet IS NULL)
        SET @null_column = '@facet'
    ELSE IF( @expression IS NULL)
        SET @null_column = '@expression'

    IF @null_column IS NOT NULL
    BEGIN
        RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_condition')
        RETURN(1)
    END

    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_conditions WHERE name = @name)
    BEGIN
        RAISERROR(34010, -1, -1, 'Condition', @name)
        RETURN(1)
    END

    SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
    IF (@facet_id IS NULL)
    BEGIN
        RAISERROR (34014, -1, -1)
        RETURN(1)
    END

    INSERT INTO msdb.dbo.syspolicy_conditions_internal(name, description,facet_id,expression,is_name_condition,obj_name) 
        VALUES(@name, @description,@facet_id,@expression,@is_name_condition,@obj_name)
    SELECT @retval = @@error
    SET @condition_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_condition_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a condition exists
-- The caller can pass either the condition name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_condition_identifiers]
@condition_name sysname = NULL OUTPUT, 
@condition_id int = NULL OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

  IF ((@condition_name IS NULL)     AND (@condition_id IS NULL)) OR
     ((@condition_name IS NOT NULL) AND (@condition_id IS NOT NULL))
  BEGIN
    RAISERROR(14524, -1, -1, '@condition_name', '@condition_id')
    RETURN(1) -- Failure
  END

  -- Check id
  IF (@condition_id IS NOT NULL)
  BEGIN
    SELECT @condition_name = name
    FROM msdb.dbo.syspolicy_conditions
    WHERE (condition_id = @condition_id)
    
    -- the view would take care of all the permissions issues.
    IF (@condition_name IS NULL) 
    BEGIN
      DECLARE @condition_id_as_char VARCHAR(36)
      SELECT @condition_id_as_char = CONVERT(VARCHAR(36), @condition_id)
      RAISERROR(14262, -1, -1, '@condition_id', @condition_id_as_char)
      RETURN(1) -- Failure
    END
  END
  ELSE
  -- Check name
  IF (@condition_name IS NOT NULL)
  BEGIN
    -- get the corresponding condition_id (if the condition exists)
    SELECT @condition_id = condition_id
    FROM msdb.dbo.syspolicy_conditions
    WHERE (name = @condition_name)
    
    -- the view would take care of all the permissions issues.
    IF (@condition_id IS NULL) 
    BEGIN
      RAISERROR(14262, -1, -1, '@condition_name', @condition_name)
      RETURN(1) -- Failure
    END
  END

  RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_condition] 
@name sysname = NULL,
@condition_id int = NULL,
@facet nvarchar(max) = NULL,
@expression nvarchar(max) = NULL,
@description nvarchar(max) = NULL,
@is_name_condition smallint = NULL,
@obj_name sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT
	DECLARE @facet_id            INT

    EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    IF (@facet IS NOT NULL)
    BEGIN
        SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
        IF (@facet_id IS NULL)
        BEGIN
            RAISERROR (34014, -1, -1)
            RETURN(1)
        END
    END

    UPDATE msdb.[dbo].[syspolicy_conditions_internal] 
    SET
        description = ISNULL(@description, description),
        facet_id = ISNULL(@facet_id, facet_id),
        expression = ISNULL(@expression, expression),
        is_name_condition = ISNULL(@is_name_condition, is_name_condition),
        obj_name = ISNULL(@obj_name, obj_name)
    WHERE condition_id = @condition_id
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_condition] 
@name sysname = NULL,
@condition_id int = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE condition_id = @condition_id)
    BEGIN
        RAISERROR(34012,-1,-1,'Condition','Policy')
        RETURN (1)
    END

    DELETE msdb.dbo.syspolicy_conditions_internal
    WHERE condition_id = @condition_id
    
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_condition]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_condition] 
@name sysname = NULL,
@condition_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    IF (@new_name IS NULL or LEN(@new_name) = 0)
    BEGIN
      RAISERROR(21263, -1, -1, '@new_name')
      RETURN(1) -- Failure
    END

    DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_condition_identifiers @name, @condition_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    UPDATE msdb.[dbo].[syspolicy_conditions_internal] 
    SET name = @new_name
    WHERE condition_id = @condition_id

    SELECT @retval = @@error
    RETURN(@retval)
END
GO

---------------------------------------------------------------
-- table for Policy category
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_categories_internal')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_policy_categories_internal]...';
    CREATE TABLE [dbo].[syspolicy_policy_categories_internal] (
        policy_category_id int IDENTITY(1,1),
        name sysname,
        mandate_database_subscriptions bit default 1 NOT NULL,
        CONSTRAINT [PK_syspolicy_policy_categories] PRIMARY KEY CLUSTERED (policy_category_id ASC),
        CONSTRAINT [UQ_syspolicy_policy_categories_name] UNIQUE(name)
        );
END
GO

PRINT 'Creating view [dbo].[syspolicy_policy_categories]...'
GO
CREATE VIEW [dbo].[syspolicy_policy_categories]
AS
    SELECT     
        policy_category_id,
        name,
        mandate_database_subscriptions
    FROM [dbo].[syspolicy_policy_categories_internal]
GO

---------------------------------------------------------------
-- ObjectSet object
---------------------------------------------------------------
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_object_sets_internal')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_object_sets_internal]...'
CREATE TABLE [dbo].[syspolicy_object_sets_internal] (
    object_set_id int NOT NULL IDENTITY(1,1),
    object_set_name sysname NOT NULL,
    facet_id int,
    CONSTRAINT [PK_syspolicy_object_sets] PRIMARY KEY CLUSTERED (object_set_id),
    CONSTRAINT [UQ_syspolicy_object_sets_name] UNIQUE(object_set_name)
)

ALTER TABLE [dbo].[syspolicy_object_sets_internal]
    ADD CONSTRAINT [FK_syspolicy_object_sets_syspolicy_management_facets] FOREIGN KEY(facet_id)
    REFERENCES [dbo].[syspolicy_management_facets] (management_facet_id)
    ON DELETE CASCADE
END
GO

PRINT 'Creating view [dbo].[syspolicy_object_sets]...'
GO
CREATE VIEW [dbo].[syspolicy_object_sets]
AS
    SELECT     
        os.object_set_id,
        os.object_set_name,
        os.facet_id,
        facet.name as facet_name
    FROM [dbo].[syspolicy_object_sets_internal] AS os INNER JOIN [dbo].[syspolicy_management_facets] AS facet
    ON os.facet_id = facet.management_facet_id
GO

-----------------------------------------------------------
-- This procedure verifies if a object set definition exists
-- The caller can pass either the name or the id
-----------------------------------------------------------
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_object_set_identifiers]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_object_set_identifiers]
@name sysname = NULL OUTPUT, 
@object_set_id int = NULL OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

  IF ((@name IS NULL)     AND (@object_set_id IS NULL)) OR
     ((@name IS NOT NULL) AND (@object_set_id IS NOT NULL))
  BEGIN
    -- TODO: Verify the error message is appropriate for object sets as well and not specific to policies
    RAISERROR(14524, -1, -1, '@name', '@object_set_id')
    RETURN(1) -- Failure
  END

  -- Check id
  IF (@object_set_id IS NOT NULL)
  BEGIN
    SELECT @name = object_set_name
    FROM msdb.dbo.syspolicy_object_sets
    WHERE (object_set_id = @object_set_id)
    
    -- the view would take care of all the permissions issues.
    IF (@name IS NULL) 
    BEGIN
        -- TODO: Where did 36 come from? Is this the total lenght of characters for an int?
      DECLARE @object_set_id_as_char VARCHAR(36)
      SELECT @object_set_id_as_char = CONVERT(VARCHAR(36), @object_set_id)
      RAISERROR(14262, -1, -1, '@object_set_id', @object_set_id_as_char)
      RETURN(1) -- Failure
    END
  END
  ELSE
  -- Check name
  IF (@name IS NOT NULL)
  BEGIN
    -- get the corresponding object_set_id (if the object_set exists)
    SELECT @object_set_id = object_set_id
    FROM msdb.dbo.syspolicy_object_sets
    WHERE (object_set_name = @name)
    
    -- the view would take care of all the permissions issues.
    IF (@object_set_id IS NULL) 
    BEGIN
    -- TODO: Verify the error message is appropriate for object sets as well and not specific to policies
      RAISERROR(14262, -1, -1, '@name', @name)
      RETURN(1) -- Failure
    END
  END

  RETURN (0)
END
GO

-----------------------------------------------------------
-- This procedure verifies if an object set is refernced (cannot be deleted)
-----------------------------------------------------------
PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_object_set_references]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_object_set_references]
@object_set_id int,
@is_referenced int OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	SELECT @is_referenced = count(*) FROM dbo.syspolicy_policies WHERE object_set_id = @object_set_id
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_object_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_object_set]
@object_set_name sysname,
@facet nvarchar (max),
@object_set_id int OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval             INT
	
	DECLARE @facet_id           INT
	DECLARE @null_column		sysname
	
	IF( @facet IS NULL)
		SET @null_column = '@facet'
		
	IF @null_column IS NOT NULL
	BEGIN
		RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_object_set')
		RETURN(1)
	END

    SET @facet_id = (SELECT management_facet_id FROM [dbo].[syspolicy_management_facets] WHERE name = @facet)
        
    IF (@facet_id IS NULL)
    BEGIN
        RAISERROR (34014, -1, -1)
        RETURN(1)
    END

    INSERT INTO msdb.[dbo].[syspolicy_object_sets_internal]
                                        (object_set_name,
                                        facet_id)
    VALUES                            
                                        (@object_set_name,
                                        @facet_id)

    SELECT @retval = @@error
    SET @object_set_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_object_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_object_set]
@object_set_name sysname = NULL,
@object_set_id int = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_object_set_identifiers @object_set_name, @object_set_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    DELETE msdb.[dbo].[syspolicy_object_sets_internal] 
        WHERE object_set_id = @object_set_id

    RETURN (0)
END
GO


---------------------------------------------------------------
-- PolicyDefinition object
---------------------------------------------------------------

IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policies_internal')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_policies_internal]...';
CREATE TABLE [dbo].[syspolicy_policies_internal] (
	policy_id int IDENTITY(1,1),
	name sysname NOT NULL,
	condition_id int NOT NULL,
	root_condition_id int NULL,
	date_created datetime  NOT NULL default GETDATE(),
	execution_mode int NOT NULL default (0),
	policy_category_id int NULL,
	schedule_uid uniqueidentifier NULL,
	description nvarchar(max) NOT NULL default (''),
	help_text nvarchar(4000) NOT NULL default (''),
	help_link nvarchar(2083) NOT NULL default (''),
	object_set_id INT NULL,
	is_enabled bit default 0 NOT NULL,
	job_id uniqueidentifier NULL,
	created_by sysname NOT NULL default SUSER_SNAME(),
	modified_by sysname NULL,
	date_modified datetime NULL,
	CONSTRAINT [PK_syspolicy_policies] PRIMARY KEY CLUSTERED (policy_id ASC),
	CONSTRAINT [UQ_syspolicy_policies_name] UNIQUE(name)
	);
ALTER TABLE [dbo].[syspolicy_policies_internal] 
    ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_conditions] FOREIGN KEY(condition_id)
    REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id);

    ALTER TABLE [dbo].[syspolicy_policies_internal] 
        ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_policy_categories] FOREIGN KEY(policy_category_id)
        REFERENCES [dbo].[syspolicy_policy_categories_internal] (policy_category_id);


ALTER TABLE [dbo].[syspolicy_policies_internal] 
    ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_root_conditions] FOREIGN KEY(root_condition_id)
    REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id);


    ALTER TABLE [dbo].[syspolicy_policies_internal] 
        ADD CONSTRAINT [FK_syspolicy_policies_sysjobs] FOREIGN KEY(job_id)
        REFERENCES [dbo].[sysjobs] (job_id);

ALTER TABLE [dbo].[syspolicy_policies_internal]
    ADD CONSTRAINT [FK_syspolicy_policies_syspolicy_object_sets] FOREIGN KEY(object_set_id)
    REFERENCES [dbo].[syspolicy_object_sets_internal] (object_set_id);
    
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_create_job]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_create_job] 
@schedule_uid uniqueidentifier,
@is_enabled bit = 0,
@jobID uniqueidentifier OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @job_name sysname

	-- create unique job name
	SET @job_name = N'syspolicy_check_schedule_' + LEFT(CONVERT(nvarchar(100), @schedule_uid), 100) 
	WHILE (EXISTS (SELECT * FROM msdb..sysjobs WHERE name = @job_name))
	BEGIN
		SET @job_name = N'syspolicy_check_schedule_' + LEFT(CONVERT(nvarchar(91), @schedule_uid), 91) + '_' + RIGHT(STR(FLOOR(RAND() * 100000000)),8) 
	END

	EXEC  msdb.dbo.sp_add_job @job_name=@job_name, 
			@enabled=@is_enabled, 
			@notify_level_eventlog=0, 
			@notify_level_email=2, 
			@notify_level_netsend=2, 
			@notify_level_page=2, 
			@delete_level=0, 
			@category_id=0, -- [Uncategorized (Local)]
			@job_id = @jobID OUTPUT

	EXEC msdb.dbo.sp_add_jobserver @job_name=@job_name, @server_name = @@servername

    EXEC msdb.dbo.sp_add_jobstep 
            @job_id=@jobID, 
			@step_name=N'Verify that automation is enabled.', 
		    @step_id=1, 
		    @cmdexec_success_code=0, 
		    @on_fail_action=1, 
		    @on_fail_step_id=0, 
		    @retry_attempts=0, 
		    @retry_interval=0, 
		    @os_run_priority=0, 
		    @subsystem=N'TSQL', 
		    @command=N'IF (msdb.dbo.fn_syspolicy_is_automation_enabled() != 1)
        BEGIN
            RAISERROR(34022, 16, 1)
        END', 
		    @database_name=N'master', 
		    @flags=0

	DECLARE @command nvarchar(max)
	SET @command = [dbo].[fn_syspolicy_get_ps_command] (@schedule_uid)

	EXEC msdb.dbo.sp_add_jobstep 
            @job_id=@jobID, 
			@step_name=N'Evaluate policies.', 
			@step_id=2, 
			@cmdexec_success_code=0, 
			@on_success_action=1, 
			@on_fail_action=2, 
			@retry_attempts=0, 
			@retry_interval=0, 
			@os_run_priority=0, 
			@subsystem=N'PowerShell', 
			@command=@command, 
			@flags=0

    EXEC msdb.dbo.sp_update_jobstep 
            @job_id = @jobID, 
            @step_id = 1, 
            @on_success_action=4, 
            @on_success_step_id=2 

	DECLARE @schedule_id int
	SELECT @schedule_id = schedule_id from msdb.dbo.sysschedules where schedule_uid = @schedule_uid

	EXEC msdb.dbo.sp_attach_schedule @job_name = @job_name, @schedule_id = @schedule_id
END
GO

PRINT 'Creating function [dbo].[fn_syspolicy_get_ps_command] ...'
GO

CREATE FUNCTION [dbo].[fn_syspolicy_get_ps_command] (@schedule_uid uniqueidentifier)
RETURNS nvarchar(max)
AS
BEGIN
	
	DECLARE @schedule_uid_string nvarchar(max);
	SET @schedule_uid_string = CONVERT(nvarchar(36), @schedule_uid);
	
	-- translate to PSPath root name, for default instances 
	-- we need to add \default as instance name
	DECLARE @root_name nvarchar(100);
	SET @root_name = @@SERVERNAME
	IF( 0 = CHARINDEX('\', @@SERVERNAME))
		SET @root_name = @root_name + N'\default';
	
	DECLARE @command nvarchar(max);
	SET @command = N'dir SQLSERVER:\SQLPolicy\' + @root_name + 
				N'\Policies | where { $_.ScheduleUid -eq "' + @schedule_uid_string + 
				N'" } |  where { $_.Enabled -eq 1} | where {$_.AutomatedPolicyEvaluationMode -eq 4} | Invoke-PolicyEvaluation -AdHocPolicyEvaluationMode 2 -TargetServerName ' + @@SERVERNAME
				
	RETURN @command
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_insert_job_create_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_insert_job_create_trigger] on [dbo].[syspolicy_policies_internal]
FOR INSERT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	DECLARE @jobID uniqueidentifier
	DECLARE @schedule_uid uniqueidentifier
	DECLARE @is_enabled bit

	-- verify that values in inserted.schedule_uid are valid
	IF EXISTS (
		SELECT * FROM inserted i 
		WHERE i.schedule_uid NOT IN 
				(SELECT schedule_uid FROM msdb.dbo.sysschedules ) AND 
		((i.execution_mode & 4) = 4))
	BEGIN
		ROLLBACK -- Failure
		RAISERROR (14365, -1, -1)
		RETURN
	END

	-- find all schedules referenced by the inserted policies for which 
	-- there is no agent job that executes the policies
	DECLARE schedule_cursor CURSOR LOCAL FOR
	    SELECT DISTINCT i.schedule_uid
	    FROM inserted i
	    WHERE 
		    ((i.execution_mode & 4) = 4) AND
	        NOT EXISTS (SELECT * 
	                        FROM msdb.dbo.syspolicy_policies p 
	                        WHERE 
	                            p.policy_id NOT IN (SELECT policy_id FROM inserted) AND
	                            p.schedule_uid = i.schedule_uid AND 
	                            ((p.execution_mode & 4) = 4) )
	
	-- iterate through the cursor and create a job for every schedule		
	OPEN schedule_cursor
	FETCH schedule_cursor INTO @schedule_uid
	WHILE @@FETCH_STATUS = 0
	BEGIN
		-- figure out if the job is enabled or not
		SELECT @is_enabled = COUNT(*) 
		FROM inserted i 
		WHERE i.schedule_uid = @schedule_uid AND i.is_enabled = 1
		
		-- explicitly nullify jobID, 
		-- (if we need to create more than 1 job, it will not be null and sp_add_job will think we're getting job from MSX)
		SET @jobID = NULL
		
		-- create the job that is going to execute the schedule
		EXEC [msdb].[dbo].[sp_syspolicy_create_job] @schedule_uid, @is_enabled, @jobID OUTPUT

		-- update the job_id back into the policies table
		UPDATE p SET p.job_id = @jobID 
			FROM msdb.dbo.syspolicy_policies_internal p
			INNER JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			i.schedule_uid = @schedule_uid AND
			(i.execution_mode & 4) = 4

		FETCH schedule_cursor INTO @schedule_uid
	END
	
	CLOSE schedule_cursor
	DEALLOCATE schedule_cursor
	
	-- in case we haven't created the job we still need to update 
	-- the policies with their jobID
	UPDATE p
		SET p.job_id = ( SELECT TOP 1 p2.job_id 
						FROM msdb.dbo.syspolicy_policies p2 
						WHERE 
							p2.schedule_uid = p.schedule_uid AND 
							p2.job_id IS NOT NULL)
		FROM msdb.dbo.syspolicy_policies_internal p
		INNER JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			((p.execution_mode & 4) = 4) AND
			p.job_id IS NULL
	
	-- See what jobs we need to enable.
	-- This can happen because we might create a new policy that 
	-- is enabled and there is already a job for it, but the existing
	-- job is disabled
	DECLARE jobs_to_enable CURSOR LOCAL FOR
		SELECT DISTINCT j.job_id
		FROM dbo.sysjobs_view j 
		JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
		JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			((i.execution_mode & 4) = 4) AND
			j.enabled = 0 AND
			EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2 
						WHERE p2.job_id = j.job_id AND p2.is_enabled = 1)
	
	OPEN jobs_to_enable
	FETCH jobs_to_enable INTO @jobID
	WHILE @@FETCH_STATUS = 0
	BEGIN
		EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 1
		
		FETCH jobs_to_enable INTO @jobID
	END
	CLOSE jobs_to_enable
	DEALLOCATE jobs_to_enable
	
	-- enable events infrastructure
	IF EXISTS ( SELECT * FROM inserted i WHERE ((i.execution_mode & 1) = 1))
	BEGIN
		EXEC sys.sp_syspolicy_update_ddl_trigger 
	END

	IF EXISTS (SELECT * FROM inserted i WHERE ((i.execution_mode & 2) = 2))
	BEGIN
		EXEC sys.sp_syspolicy_update_event_notification 
	END

	-- update owner information
	UPDATE msdb.dbo.syspolicy_policies_internal
	SET created_by = original_login(),
		date_created = getdate (),
		date_modified = NULL,
		modified_by = NULL
	FROM inserted i,
	   msdb.dbo.syspolicy_policies_internal policies
	WHERE i.policy_id = policies.policy_id

	-- protect against non-scheduled automation jobs
	-- that have expressions that execute script
	DECLARE @row_count int

    SELECT @row_count = count(*) 
        FROM syspolicy_conditions c  
        INNER JOIN inserted i ON (i.condition_id = c.condition_id OR i.root_condition_id = c.condition_id)
        WHERE    i.is_enabled != 0 AND
                i.execution_mode != 4 AND
                (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) ) 
        OPTION (FORCE ORDER);

    SELECT @row_count = @row_count + count(*)
        FROM dbo.syspolicy_target_set_levels l 
        INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
        INNER JOIN syspolicy_conditions c on c.condition_id = l.condition_id
        INNER JOIN syspolicy_object_sets_internal os ON os.object_set_id = s.object_set_id
        INNER JOIN inserted i ON os.object_set_id = i.object_set_id
        WHERE    i.is_enabled != 0 AND
                i.execution_mode != 4 AND
                (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
        OPTION (FORCE ORDER);

    IF (@row_count > 0)
    BEGIN
        RAISERROR(34017, -1, -1);
        ROLLBACK TRANSACTION;
    END

END -- create trigger
GO

PRINT 'Creating trigger [dbo].[syspolicy_update_job_update_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_update_job_update_trigger] on [dbo].[syspolicy_policies_internal]
FOR UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	-- This is to prevent indirect entrance of the trigger
	IF (TRIGGER_NESTLEVEL() > 1) RETURN

	-- verify that values in inserted.schedule_uid are valid
	IF EXISTS (
		SELECT * FROM inserted i 
		WHERE i.schedule_uid NOT IN 
				(SELECT schedule_uid FROM msdb.dbo.sysschedules ) AND 
		((i.execution_mode & 4) = 4))
	BEGIN
		ROLLBACK -- Failure
		RAISERROR (14365, -1, -1)
		RETURN
	END

	-- update eventing infrastructure
	IF(UPDATE(execution_mode) OR UPDATE(is_enabled))
	BEGIN
		IF  EXISTS (SELECT * 
					FROM inserted i
					INNER JOIN deleted d ON i.policy_id = d.policy_id
					WHERE 
						(((i.execution_mode & 1) = 1) OR ((d.execution_mode & 1) = 1)) AND 
						(i.is_enabled != d.is_enabled OR i.execution_mode != d.execution_mode))
		BEGIN
			EXEC sys.sp_syspolicy_update_ddl_trigger 
		END

		IF  EXISTS (SELECT * 
					FROM inserted i
					INNER JOIN deleted d ON i.policy_id = d.policy_id
					WHERE 
						(((i.execution_mode & 2) = 2) OR ((d.execution_mode & 2) = 2)) AND 
						(i.is_enabled != d.is_enabled OR i.execution_mode != d.execution_mode))
		BEGIN
			EXEC sys.sp_syspolicy_update_event_notification 
		END
	END

	DECLARE @jobID uniqueidentifier
	DECLARE @is_enabled bit
	DECLARE @schedule_uid uniqueidentifier

    -- set the job_id to NULL for all policies whose schedule_uid has changed
    -- so that we can create a job if needed
    UPDATE p
        SET p.job_id = NULL
        FROM msdb.dbo.syspolicy_policies p
        INNER JOIN inserted i ON p.policy_id = i.policy_id
        INNER JOIN deleted d ON d.policy_id = p.policy_id
        WHERE i.schedule_uid != d.schedule_uid

	-- find all schedules referenced by the inserted policies for which 
	-- there is no agent job that executes the policies
	DECLARE schedule_cursor CURSOR LOCAL FOR
	    SELECT DISTINCT i.schedule_uid
	    FROM inserted i
	    WHERE 
		    ((i.execution_mode & 4) = 4) AND
	        NOT EXISTS (SELECT * 
	                        FROM msdb.dbo.syspolicy_policies p 
	                        WHERE 
	                            p.schedule_uid = i.schedule_uid AND 
	                            ((p.execution_mode & 4) = 4) AND
	                            p.job_id IS NOT NULL)
	                    
	-- iterate through the cursor and create a job for every schedule		
	OPEN schedule_cursor
	FETCH schedule_cursor INTO @schedule_uid
	WHILE @@FETCH_STATUS = 0
	BEGIN
		-- figure out if the job is enabled or not
		SELECT @is_enabled = COUNT(*) 
		FROM inserted i 
		WHERE i.schedule_uid = @schedule_uid AND i.is_enabled = 1
		
		-- create the job that is going to execute the schedule
		EXEC [msdb].[dbo].[sp_syspolicy_create_job] @schedule_uid, @is_enabled, @jobID OUTPUT

		-- update the job_id back into the policies table
		UPDATE p SET p.job_id = @jobID 
			FROM msdb.dbo.syspolicy_policies_internal p
			INNER JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			i.schedule_uid = @schedule_uid AND
			(i.execution_mode & 4) = 4
	
		FETCH schedule_cursor INTO @schedule_uid
	END
	
	CLOSE schedule_cursor
	DEALLOCATE schedule_cursor
	
	-- in case we haven't created the job we still need to update 
	-- the policies with their jobID
	UPDATE p 
		SET p.job_id = ( SELECT TOP 1 p2.job_id 
						FROM msdb.dbo.syspolicy_policies p2 
						WHERE 
							p2.schedule_uid = p.schedule_uid AND
							p2.job_id IS NOT NULL)
		FROM msdb.dbo.syspolicy_policies p
		INNER JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			((p.execution_mode & 4) = 4) AND
			p.job_id IS NULL
	
	-- if the execution_mode has changed then we need to clear the job references
	UPDATE p
		SET p.job_id = NULL
		FROM msdb.dbo.syspolicy_policies_internal p
		INNER JOIN inserted i ON p.policy_id = i.policy_id 
		INNER JOIN deleted d ON p.policy_id = d.policy_id
		WHERE 
			((i.execution_mode & 4) != 4) AND
			((d.execution_mode & 4) = 4) AND
			p.job_id IS NOT NULL
	
	-- See what jobs we need to enable.
	-- This can happen because we might create a new policy that 
	-- is enabled and there is already a job for it, but the existing
	-- job is disabled
	DECLARE jobs_to_enable CURSOR LOCAL FOR
		SELECT DISTINCT j.job_id
		FROM dbo.sysjobs_view j 
		JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
		JOIN inserted i ON p.policy_id = i.policy_id
		WHERE 
			((i.execution_mode & 4) = 4) AND
			j.enabled = 0 AND
			EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2 
						WHERE p2.job_id = j.job_id AND p2.is_enabled = 1)
	
	OPEN jobs_to_enable
	FETCH jobs_to_enable INTO @jobID
	WHILE @@FETCH_STATUS = 0
	BEGIN
		EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 1
		
		FETCH jobs_to_enable INTO @jobID
	END
	CLOSE jobs_to_enable
	DEALLOCATE jobs_to_enable

	-- Find out what jobs have to be deleted because the policy's schedule 
	-- has changed
	IF (UPDATE(schedule_uid))
	BEGIN
		DECLARE deleted_cursor CURSOR LOCAL FOR 
			SELECT DISTINCT d.job_id
			FROM deleted d
			WHERE 
				((d.execution_mode & 4) = 4) AND
				d.job_id NOT IN (SELECT job_id FROM msdb.dbo.syspolicy_policies p 
								WHERE 
								((p.execution_mode & 4) = 4))

		OPEN deleted_cursor
		FETCH deleted_cursor INTO @jobID
		
		WHILE (@@FETCH_STATUS=0)
		BEGIN
			-- delete the job(s), but do not delete the shared schedule
			IF (@jobID IS NOT NULL)
				EXEC msdb.dbo.sp_delete_job @job_id = @jobID, @delete_unused_schedule = 0

			FETCH deleted_cursor INTO @jobID
		END -- while (@@FETCH_STATUS=0)

		CLOSE deleted_cursor
		DEALLOCATE deleted_cursor
	END	-- UPDATE(schedule_uid)


	-- See what jobs we need to disable.
	-- This can happen because we do not need to delete the job, but
	-- all policies that reference it are disabled.
	DECLARE jobs_to_disable CURSOR LOCAL FOR
		SELECT DISTINCT j.job_id
		FROM dbo.sysjobs_view j 
		JOIN msdb.dbo.syspolicy_policies p ON p.job_id = j.job_id
		WHERE 
			j.enabled = 1 AND
			NOT EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2 
						WHERE p2.job_id = j.job_id AND p2.is_enabled = 1 AND ((p2.execution_mode & 4) = 4))
	
	OPEN jobs_to_disable
	FETCH jobs_to_disable INTO @jobID
	WHILE @@FETCH_STATUS = 0
	BEGIN
		EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 0
		
		FETCH jobs_to_disable INTO @jobID
	END
	CLOSE jobs_to_disable
	DEALLOCATE jobs_to_disable

    UPDATE msdb.dbo.syspolicy_policies_internal
    SET modified_by = original_login(),
        date_modified = GETDATE()
    FROM inserted i,
       msdb.dbo.syspolicy_policies_internal policies
    WHERE i.policy_id = policies.policy_id
END -- update trigger
GO

PRINT 'Creating trigger [dbo].[syspolicy_insert_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_insert_policy_trigger] on [dbo].[syspolicy_policies_internal]
FOR INSERT
AS
BEGIN
    DECLARE @object_set_id int, @name sysname

	SELECT TOP 1 @object_set_id = i.object_set_id, @name = i.name 
	FROM inserted i 
	WHERE 1 < (SELECT count(*) FROM syspolicy_policies p WHERE p.object_set_id = i.object_set_id)

	IF @@ROWCOUNT > 0
	BEGIN
				DECLARE @os_name sysname, @policy_name sysname
				SELECT TOP 1 @os_name = os.object_set_name, @policy_name = p.name
				 FROM syspolicy_object_sets os 
					INNER JOIN syspolicy_policies p ON (os.object_set_id = p.object_set_id)
				WHERE os.object_set_id = @object_set_id AND p.name <> @name
				
				RAISERROR(34013, -1, -1, 'ObjectSet', @os_name, @policy_name) 
				ROLLBACK TRANSACTION
	END
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_update_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_update_policy_trigger] on [dbo].[syspolicy_policies_internal]
FOR UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END
	
	-- This is to prevent indirect execution of the trigger
	IF (TRIGGER_NESTLEVEL() > 1) RETURN

    IF( UPDATE(condition_id) )
    BEGIN
        -- delete all health state records for active policies whose 
        -- condition has changed
        DELETE FROM [dbo].[syspolicy_system_health_state_internal] 
            FROM [dbo].[syspolicy_system_health_state_internal] phs
            INNER JOIN inserted i ON phs.policy_id = i.policy_id
            INNER JOIN deleted d ON phs.policy_id = d.policy_id
            WHERE d.condition_id != i.condition_id AND i.is_enabled = 1
    END

    IF( UPDATE(object_set_id) )
    BEGIN
        DECLARE @object_set_id int, @numref int, @new_object_set_id int, @name sysname
        
        DECLARE os_cursor CURSOR LOCAL FOR 
        SELECT i.object_set_id, d.object_set_id, i.name
        FROM inserted i INNER JOIN deleted d ON (i.policy_id = d.policy_id) 
        WHERE (d.object_set_id IS NOT NULL AND i.object_set_id IS NULL)
			OR (i.object_set_id IS NOT NULL AND d.object_set_id IS NULL)
			OR (d.object_set_id != i.object_set_id)

        OPEN os_cursor
        FETCH os_cursor INTO @new_object_set_id, @object_set_id, @name
    
        WHILE @@FETCH_STATUS = 0 
        BEGIN
			IF (@object_set_id IS NOT NULL)
			BEGIN
				EXEC sp_syspolicy_verify_object_set_references @object_set_id, @numref OUTPUT
				IF (@numref = 0)
					EXEC sp_syspolicy_delete_object_set @object_set_id=@object_set_id
            END
            
			IF (@new_object_set_id IS NOT NULL)
			BEGIN
				EXEC sp_syspolicy_verify_object_set_references @new_object_set_id, @numref OUTPUT
				IF (@numref > 1)
				BEGIN
					DECLARE @os_name sysname, @policy_name sysname
					SELECT TOP 1 @os_name = os.object_set_name, @policy_name = p.name
					 FROM syspolicy_object_sets os 
						INNER JOIN syspolicy_policies p ON (os.object_set_id = p.object_set_id)
					WHERE os.object_set_id = @object_set_id AND p.name <> @name
					
					RAISERROR(34013, -1, -1, 'ObjectSet', @os_name, @policy_name) 
					ROLLBACK TRANSACTION
				END
            END
                
            FETCH os_cursor INTO @new_object_set_id, @object_set_id, @name
        END
            
        CLOSE os_cursor
        DEALLOCATE os_cursor    

    END

    IF( UPDATE(is_enabled) )
    BEGIN
        -- delete all health state records for policies that 
        -- have been disabled
        DELETE FROM [dbo].[syspolicy_system_health_state_internal] 
            FROM [dbo].[syspolicy_system_health_state_internal] phs
            INNER JOIN inserted i ON phs.policy_id = i.policy_id
            INNER JOIN deleted d ON phs.policy_id = d.policy_id
            WHERE d.is_enabled = 1 AND i.is_enabled = 0
    END

    IF( UPDATE(is_enabled) )
    BEGIN
        DECLARE @row_count int

        SELECT @row_count = count(*) 
            FROM syspolicy_conditions c  
            INNER JOIN inserted i ON (i.condition_id = c.condition_id OR i.root_condition_id = c.condition_id)
            WHERE    i.is_enabled != 0 AND
                    i.execution_mode != 4 AND
                    (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                    1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) ) 
            OPTION (FORCE ORDER)

        SELECT @row_count = @row_count + count(*)
            FROM dbo.syspolicy_target_set_levels l 
            INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
            INNER JOIN syspolicy_conditions c on c.condition_id = l.condition_id
            INNER JOIN syspolicy_object_sets_internal os on os.object_set_id = s.object_set_id
            INNER JOIN inserted i ON os.object_set_id = i.object_set_id
            WHERE    i.is_enabled != 0 AND
                    i.execution_mode != 4 AND
                    (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                    1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
            OPTION (FORCE ORDER)

        IF (@row_count > 0)
        BEGIN
            RAISERROR(34017, -1, -1) 
            ROLLBACK TRANSACTION
        END
    END
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_delete_job_delete_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_delete_job_delete_trigger] on [dbo].[syspolicy_policies_internal]
FOR DELETE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	DECLARE @jobID uniqueidentifier 

	-- Declare the cursor to iterate over the jobs that are only referenced 
	-- by deleted policies. The jobs that are still referenced by active policies 
	-- should not be deleted.
	DECLARE deleted_cursor CURSOR LOCAL FOR 
		SELECT DISTINCT d.job_id
		FROM deleted d
		WHERE 
			((d.execution_mode & 4) = 4) AND
			NOT EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies p 
							WHERE 
							p.job_id = d.job_id AND 
							((p.execution_mode & 4) = 4) AND
							p.policy_id NOT IN (SELECT d2.policy_id FROM deleted d2))

	OPEN deleted_cursor
	FETCH deleted_cursor INTO @jobID
	
	WHILE (@@FETCH_STATUS=0)
	BEGIN
		-- delete the job(s), but do not delete the shared schedule
		IF (@jobID IS NOT NULL)
			EXEC msdb.dbo.sp_delete_job @job_id = @jobID, @delete_unused_schedule = 0

		FETCH deleted_cursor INTO @jobID
	END -- while (@@FETCH_STATUS=0)

    CLOSE deleted_cursor
    DEALLOCATE deleted_cursor


	-- See what jobs we need to disable.
	-- This can happen because we do not need to delete the job, but
	-- all policies that reference it are disabled.
	DECLARE jobs_to_disable CURSOR LOCAL FOR
		SELECT DISTINCT j.job_id
		FROM dbo.sysjobs_view j 
		JOIN deleted d ON d.job_id = j.job_id
		WHERE 
			j.enabled = 1 AND
			NOT EXISTS ( SELECT * from msdb.dbo.syspolicy_policies p2 
						WHERE p2.job_id = j.job_id AND p2.is_enabled = 1 AND ((p2.execution_mode & 4) = 4))
	
	OPEN jobs_to_disable
	FETCH jobs_to_disable INTO @jobID
	WHILE @@FETCH_STATUS = 0
	BEGIN
		EXEC msdb.dbo.sp_update_job @job_id = @jobID, @enabled = 0
		
		FETCH jobs_to_disable INTO @jobID
	END
	CLOSE jobs_to_disable
	DEALLOCATE jobs_to_disable

	-- update eventing infrastructure
	IF EXISTS ( SELECT * FROM deleted d WHERE ((d.execution_mode & 1) = 1))
	BEGIN
		EXEC sys.sp_syspolicy_update_ddl_trigger 
	END

	IF EXISTS (SELECT * FROM deleted d WHERE ((d.execution_mode & 2) = 2))
	BEGIN
		EXEC sys.sp_syspolicy_update_event_notification 
	END

END
GO

PRINT 'Creating trigger [dbo].[syspolicy_instead_delete_policy_trigger] on [dbo].[syspolicy_policies_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_instead_delete_policy_trigger] on [dbo].[syspolicy_policies_internal]
INSTEAD OF DELETE 
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	-- This trigger deletes references in given order to protect from deadlocks
	DELETE msdb.dbo.syspolicy_policy_execution_history_internal	WHERE policy_id in (SELECT policy_id FROM deleted)
	DELETE msdb.dbo.syspolicy_system_health_state_internal		WHERE policy_id in (SELECT policy_id FROM deleted)
	DELETE msdb.dbo.syspolicy_policies_internal		WHERE policy_id in (SELECT policy_id FROM deleted)
END
GO

PRINT 'Creating view [dbo].[syspolicy_policies]...'
GO
CREATE VIEW [dbo].[syspolicy_policies]
AS
    SELECT     
        policy_id,
        name,
        condition_id,
        root_condition_id,
        date_created,
        execution_mode,
        policy_category_id,
        schedule_uid,
        description,
        help_text,
        help_link,
        object_set_id,
        is_enabled,
        job_id,
        created_by,
        modified_by,
        date_modified
    FROM [dbo].[syspolicy_policies_internal]
GO

PRINT ''
PRINT 'Creating trigger syspolicy_insert_condition_trigger...'
GO

CREATE TRIGGER dbo.syspolicy_insert_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
AFTER INSERT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

  UPDATE msdb.dbo.syspolicy_conditions_internal
  SET created_by = original_login()
  FROM inserted i INNER JOIN
       msdb.dbo.syspolicy_conditions_internal conditions
  ON i.condition_id = conditions.condition_id

END
GO


PRINT ''
PRINT 'Creating trigger dbo.syspolicy_for_update_condition_trigger...'
GO

CREATE TRIGGER dbo.syspolicy_for_update_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
FOR UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	-- This is to prevent indirect entrance of the trigger
	IF (TRIGGER_NESTLEVEL() > 1) 
		RETURN

    -- do not allow expression to be changed to a script 
    -- if the policy is enabled
    IF UPDATE(expression)
    BEGIN
        DECLARE @row_count int

        SELECT @row_count = count(*) 
            FROM inserted i 
            INNER JOIN syspolicy_policies p ON (i.condition_id = p.condition_id OR p.root_condition_id = i.condition_id)
            WHERE    p.is_enabled != 0 AND
                    p.execution_mode != 4 AND
                    (1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                    1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) ) 
            OPTION (FORCE ORDER)

        SELECT @row_count = @row_count + count(*)
            FROM dbo.syspolicy_target_set_levels l 
            INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = l.target_set_id
            INNER JOIN inserted i on i.condition_id = l.condition_id
            INNER JOIN syspolicy_object_sets_internal os ON s.object_set_id = os.object_set_id
            INNER JOIN syspolicy_policies p ON os.object_set_id = p.object_set_id
            WHERE    p.is_enabled != 0 AND
                    p.execution_mode != 4 AND
                    (1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteSql"]' ) OR
                    1 = CONVERT(xml, i.expression).exist('//FunctionType/text()[.="ExecuteWql"]' ) )
            OPTION (FORCE ORDER)

        IF (@row_count > 0)
        BEGIN
            RAISERROR(34017, -1, -1) 
            ROLLBACK TRANSACTION
        END

    END
END
GO

PRINT ''
PRINT 'Creating trigger syspolicy_after_update_condition_trigger...'
GO

CREATE TRIGGER dbo.syspolicy_after_update_condition_trigger
ON msdb.dbo.syspolicy_conditions_internal
AFTER UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	-- This is to prevent indirect entrance of the trigger
	IF (TRIGGER_NESTLEVEL() > 1) 
		RETURN

    UPDATE msdb.dbo.syspolicy_conditions_internal
        SET modified_by = original_login(), date_modified = GETDATE()
        FROM inserted i 
        INNER JOIN msdb.dbo.syspolicy_conditions_internal c ON i.condition_id = c.condition_id

    -- update health state table by deleting all the records for 
    -- policies whose expression has been modified
    IF UPDATE(expression)
    BEGIN
        DELETE FROM dbo.syspolicy_system_health_state_internal 
            FROM dbo.syspolicy_system_health_state_internal phs
            INNER JOIN dbo.syspolicy_policies p ON phs.policy_id = p.policy_id
            INNER JOIN inserted i ON p.condition_id = i.condition_id
            INNER JOIN deleted d ON p.condition_id = d.condition_id
            WHERE d.expression != i.expression 
    END
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_policy_category_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a policy category exists
-- The caller can pass either the policy category name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_policy_category_identifiers]
@policy_category_name sysname = NULL OUTPUT, 
@policy_category_id int = NULL OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

  IF ((@policy_category_name IS NULL)     AND (@policy_category_id IS NULL)) OR
     ((@policy_category_name IS NOT NULL) AND (@policy_category_id IS NOT NULL))
  BEGIN
    RAISERROR(14524, -1, -1, '@policy_category_name', '@policy_category_id')
    RETURN(1) -- Failure
  END

  -- Check id
  IF (@policy_category_id IS NOT NULL)
  BEGIN
    SELECT @policy_category_name = name
    FROM msdb.dbo.syspolicy_policy_categories
    WHERE (policy_category_id = @policy_category_id)
    
    -- the view would take care of all the permissions issues.
    IF (@policy_category_name IS NULL) 
    BEGIN
      DECLARE @policy_category_id_as_char VARCHAR(36)
      SELECT @policy_category_id_as_char = CONVERT(VARCHAR(36), @policy_category_id)
      RAISERROR(14262, -1, -1, '@policy_category_id', @policy_category_id_as_char)
      RETURN(1) -- Failure
    END
  END
  ELSE
  -- Check name
  IF (@policy_category_name IS NOT NULL)
  BEGIN
    -- get the corresponding policy_category_id (if the condition exists)
    SELECT @policy_category_id = policy_category_id
    FROM msdb.dbo.syspolicy_policy_categories
    WHERE (name = @policy_category_name)
    
    -- the view would take care of all the permissions issues.
    IF (@policy_category_id IS NULL) 
    BEGIN
      RAISERROR(14262, -1, -1, '@policy_category_name', @policy_category_name)
      RETURN(1) -- Failure
    END
  END

  RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy_category]
@name sysname,
@mandate_database_subscriptions bit = 1,
@policy_category_id int OUTPUT 
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval			INT
	DECLARE @null_column	sysname
	
	SET @null_column = NULL
	
	IF(@name IS NULL OR @name = N'')
		SET @null_column = '@name'

    IF @null_column IS NOT NULL
    BEGIN
        RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_policy_category')
        RETURN(1)
    END

    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policy_categories_internal WHERE name = @name)
    BEGIN
        RAISERROR(34010, -1, -1, 'Policy Category', @name)
        RETURN(1)
    END

    INSERT INTO msdb.dbo.syspolicy_policy_categories_internal(name, mandate_database_subscriptions) VALUES (@name, @mandate_database_subscriptions)
    SELECT @retval = @@error
    SET @policy_category_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy_category]
@name sysname = NULL,
@policy_category_id int = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policy_category_subscriptions WHERE policy_category_id = @policy_category_id)
    BEGIN
        RAISERROR(34012,-1,-1,'Policy Category','Policy Subscription')
        RETURN (1)
    END


    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE policy_category_id = @policy_category_id)
    BEGIN
        RAISERROR(34012,-1,-1,'Policy Category','Policy')
        RETURN (1)
    END

    DELETE msdb.dbo.syspolicy_policy_categories_internal
    WHERE policy_category_id = @policy_category_id
    
    SET @retval = @@error
    RETURN @retval
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_policy_category] 
@name sysname = NULL,
@policy_category_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    IF (@new_name IS NULL or LEN(@new_name) = 0)
    BEGIN
      RAISERROR(21263, -1, -1, '@new_name')
      RETURN(1) -- Failure
    END

    DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    UPDATE msdb.[dbo].[syspolicy_policy_categories_internal ]
    SET name = @new_name
    WHERE policy_category_id = @policy_category_id

    SELECT @retval = @@error
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy_category]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy_category] 
@name sysname = NULL,
@policy_category_id int = NULL,
@mandate_database_subscriptions bit = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_policy_category_identifiers @name, @policy_category_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    UPDATE msdb.[dbo].[syspolicy_policy_categories_internal ]
    SET mandate_database_subscriptions = ISNULL(@mandate_database_subscriptions, mandate_database_subscriptions)
    WHERE policy_category_id = @policy_category_id

    SELECT @retval = @@error
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy] 
@name sysname,
@condition_id int = NULL,
@condition_name sysname = NULL,
@schedule_uid uniqueidentifier = NULL,
@policy_category sysname = NULL,
@description nvarchar(max) = N'',
@help_text nvarchar(4000) = N'',
@help_link nvarchar(2083) = N'',
@execution_mode int,
@is_enabled bit = 0,
@root_condition_id int = NULL,
@root_condition_name sysname = NULL,
@object_set sysname = NULL,
@policy_id int = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
    DECLARE @retval_check int;
    EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
    IF ( 0!= @retval_check)
    BEGIN
        RETURN @retval_check
    END

    DECLARE @retval         INT
    DECLARE @null_column    sysname
    
    SET @null_column = NULL

    IF (@name IS NULL OR @name = N'')
        SET @null_column = '@name'
    ELSE IF (@execution_mode IS NULL )
        SET @null_column = '@execution_mode'
    ELSE IF( @is_enabled IS NULL)
        SET @null_column = '@is_enabled'
    ELSE IF( @description IS NULL)
        SET @null_column = '@description'
    ELSE IF( @help_text IS NULL)
        SET @null_column = '@help_text'
    ELSE IF( @help_link IS NULL)
        SET @null_column = '@help_link'
    

    IF @null_column IS NOT NULL
    BEGIN
        RAISERROR(14043, -1, -1, @null_column, 'sp_syspolicy_add_policy')
        RETURN(1)
    END

    IF EXISTS (SELECT * FROM msdb.dbo.syspolicy_policies WHERE name = @name)
    BEGIN
        RAISERROR(34010, -1, -1, 'Policy', @name)
        RETURN(1)
    END

    SET @schedule_uid = ISNULL (@schedule_uid, '{00000000-0000-0000-0000-000000000000}')

    --Check for the execution mode value
    IF (@execution_mode NOT IN (0,1,2,4,5,6))
    BEGIN 
        RAISERROR(34004, -1, -1, @execution_mode)
        RETURN (1)
    END

    IF (@schedule_uid = '{00000000-0000-0000-0000-000000000000}' AND (@execution_mode & 4) = 4)
    BEGIN
        RAISERROR (34011, -1, -1, 'schedule_uid', 4)
        RETURN(1)
    END

    IF (@is_enabled = 1 AND @execution_mode = 0)
    BEGIN
        RAISERROR (34011, -1, -1, 'is_enabled', @execution_mode)
        RETURN(1)
    END

    -- Turn [nullable] empty string parameters into NULLs
    IF @condition_name = '' SELECT @condition_name = NULL
    IF @policy_category = ''   SELECT @policy_category = NULL
    IF @root_condition_name = '' SELECT @root_condition_name = NULL

    -- verify that the condition exists
    EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
    IF (@retval <> 0)
        RETURN(1)
        
    -- convert @object_set into id if needed
    DECLARE @object_set_id INT
    DECLARE @object_set_facet_id INT
    IF (@object_set IS NOT NULL)
    BEGIN
        SELECT @object_set_id = object_set_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
        IF @object_set_id IS NULL
        BEGIN
            -- TODO: RAISERROR that specified object set doesn't exist
            RAISERROR(N'specified object set does not exists', -1, -1)
            RETURN(1) -- Failure
        END
        ELSE
        BEGIN
            SELECT @object_set_facet_id = facet_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
            -- Ensure the object set has been created from the same facet that the policy condition has been created
            IF (@object_set_facet_id <> (SELECT facet_id FROM msdb.dbo.syspolicy_conditions_internal WHERE condition_id = @condition_id))
            BEGIN
                -- TODO: RAISEERROR that specified object_set isn't created from the facet that the policy condition has been created from
                RAISERROR(N'specified object set does not match facet the policy condition was created off', -1, -1)
                RETURN(1) -- Failure
            END
        END
    END

    IF (@root_condition_name IS NOT NULL) OR (@root_condition_id IS NOT NULL)
    BEGIN
        -- verify that the root condition exists
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @root_condition_name OUTPUT, @condition_id = @root_condition_id OUTPUT
        IF (@retval <> 0)
            RETURN(1)
            
        -- Check execution mode for compatibility with root_condition
        IF (@execution_mode = 1) OR (@execution_mode = 2) -- Enforce or Check on Change
        BEGIN
            RAISERROR (34011, -1, -1, 'root_condition', @execution_mode)
            RETURN(1)
        END

    END

    -- verify schedule
    IF (@schedule_uid != '{00000000-0000-0000-0000-000000000000}')
    BEGIN
        IF NOT EXISTS (SELECT * FROM msdb.dbo.sysschedules WHERE schedule_uid = @schedule_uid)
        BEGIN
            RAISERROR(14365, -1, -1)
            RETURN(1) -- Failure
        END
    END

    -- convert group_name into id if needed
    DECLARE @policy_category_id INT
    IF ( (@policy_category IS NOT NULL) )
    BEGIN 
        IF NOT EXISTS (SELECT * from msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category)
        BEGIN
            RAISERROR(34015, -1, -1,@policy_category)
            RETURN(1) -- Failure
        END
        ELSE
            SELECT @policy_category_id = policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category
    END
    
    INSERT INTO msdb.dbo.syspolicy_policies_internal
                                        (name, 
                                        execution_mode, 
                                        schedule_uid,
                                        policy_category_id,
                                        description,
                                        help_text,
                                        help_link,
                                        condition_id,
                                        root_condition_id,
                                        object_set_id,
                                        is_enabled)
    VALUES                            
                                        (@name, 
                                        @execution_mode, 
                                        @schedule_uid,
                                        @policy_category_id,
                                        @description,
                                        @help_text,
                                        @help_link,
                                        @condition_id,
                                        @root_condition_id,
                                        @object_set_id,
                                        @is_enabled)

    SELECT @retval = @@error
    SET @policy_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_verify_policy_identifiers]...'
GO
-----------------------------------------------------------
-- This procedure verifies if a policy definition exists
-- The caller can pass either the name or the id
-----------------------------------------------------------
CREATE PROCEDURE [dbo].[sp_syspolicy_verify_policy_identifiers]
@name sysname = NULL OUTPUT, 
@policy_id int = NULL OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

  IF ((@name IS NULL)     AND (@policy_id IS NULL)) OR
     ((@name IS NOT NULL) AND (@policy_id IS NOT NULL))
  BEGIN
    RAISERROR(14524, -1, -1, '@name', '@policy_id')
    RETURN(1) -- Failure
  END

  -- Check id
  IF (@policy_id IS NOT NULL)
  BEGIN
    SELECT @name = name
    FROM msdb.dbo.syspolicy_policies
    WHERE (policy_id = @policy_id)
    
    -- the view would take care of all the permissions issues.
    IF (@name IS NULL) 
    BEGIN
      DECLARE @policy_id_as_char VARCHAR(36)
      SELECT @policy_id_as_char = CONVERT(VARCHAR(36), @policy_id)
      RAISERROR(14262, -1, -1, '@policy_id', @policy_id_as_char)
      RETURN(1) -- Failure
    END
  END
  ELSE
  -- Check name
  IF (@name IS NOT NULL)
  BEGIN
    -- get the corresponding policy_id (if the policy exists)
    SELECT @policy_id = policy_id
    FROM msdb.dbo.syspolicy_policies
    WHERE (name = @name)
    
    -- the view would take care of all the permissions issues.
    IF (@policy_id IS NULL) 
    BEGIN
      RAISERROR(14262, -1, -1, '@name', @name)
      RETURN(1) -- Failure
    END
  END

  RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_rename_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_rename_policy] 
@name sysname = NULL,
@policy_id int = NULL,
@new_name sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    IF (@new_name IS NULL or LEN(@new_name) = 0)
    BEGIN
      RAISERROR(21263, -1, -1, '@new_name')
      RETURN(1) -- Failure
    END

    DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    UPDATE msdb.[dbo].[syspolicy_policies_internal] 
    SET name = @new_name
    WHERE policy_id = @policy_id

    SELECT @retval = @@error
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy] 
@name sysname = NULL,
@policy_id int = NULL,
@condition_id int=NULL,
@condition_name sysname = NULL,
@execution_mode int=NULL,
@policy_category sysname = NULL,
@schedule_uid uniqueidentifier = NULL,
@description nvarchar(max) = NULL,
@help_text nvarchar(4000) = NULL,
@help_link nvarchar(2083) = NULL,
@root_condition_id int = -1,
@root_condition_name sysname = NULL,
@object_set_id int = -1,
@object_set sysname = NULL,
@is_enabled bit = NULL
WITH EXECUTE AS OWNER
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	--Check for the execution mode value
	IF (((@execution_mode IS NOT NULL)) AND (@execution_mode NOT IN (0,1,2,4,5,6)))
	BEGIN 
		RAISERROR(34004, -1, -1, @execution_mode)
		RETURN (1)
	END

    -- Turn [nullable] empty string parameters into NULLs
    IF @name = ''           SELECT @name = NULL
    IF @condition_name = '' SELECT @condition_name = NULL
    IF @root_condition_name = '' 
        BEGIN
        SELECT @root_condition_name = NULL
        IF @root_condition_id = -1
            -- root_condition is being reset
            SELECT @root_condition_id = NULL
        END
    IF @object_set = '' 
        BEGIN
        SELECT @object_set = NULL
        IF @object_set_id = -1
            -- object_set is being reset
            SELECT @object_set_id = NULL
        END

    DECLARE @retval              INT

    EXEC @retval = msdb.dbo.sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    SELECT  @execution_mode = ISNULL(@execution_mode, execution_mode),
            @is_enabled = ISNULL(@is_enabled, is_enabled) 
        FROM msdb.dbo.syspolicy_policies WHERE policy_id = @policy_id

    IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
    BEGIN
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
        IF (@retval <> 0)
            RETURN (1)
    END

    IF((@root_condition_id IS NOT NULL and @root_condition_id != -1) or @root_condition_name IS NOT NULL)
    BEGIN
        IF (@root_condition_id = -1 and @root_condition_name IS NOT NULL)
            SET @root_condition_id = NULL
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @root_condition_name OUTPUT, @condition_id = @root_condition_id OUTPUT
        IF (@retval <> 0)
            RETURN (1)
    END

    SET @schedule_uid = ISNULL (@schedule_uid, '{00000000-0000-0000-0000-000000000000}')

    IF (@schedule_uid = '{00000000-0000-0000-0000-000000000000}' AND (@execution_mode & 4) = 4)
    BEGIN
        RAISERROR (34011, -1, -1, 'schedule_uid', 4)
        RETURN(1)
    END

    IF (@is_enabled = 1 AND @execution_mode = 0)
    BEGIN
        RAISERROR (34011, -1, -1, 'is_enabled', @execution_mode)
        RETURN(1)
    END

    IF (@schedule_uid != '{00000000-0000-0000-0000-000000000000}')
    BEGIN
        -- verify the schedule exists
        IF NOT EXISTS (SELECT schedule_id FROM msdb.dbo.sysschedules WHERE schedule_uid = @schedule_uid)
        BEGIN
            RAISERROR (14365, -1, -1)
            RETURN(1)
        END
    END

    DECLARE @object_set_facet_id INT
    IF ((@object_set_id IS NOT NULL and @object_set_id != -1) or @object_set IS NOT NULL)
    BEGIN
        IF (@object_set_id = -1 and @object_set IS NOT NULL)
            SET @object_set_id = NULL
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_object_set_identifiers @name = @object_set OUTPUT, @object_set_id = @object_set_id OUTPUT
        IF (@retval <> 0)
            RETURN (1)

        SELECT @object_set_facet_id = facet_id FROM msdb.dbo.syspolicy_object_sets WHERE object_set_name = @object_set
        -- Ensure the object set has been created from the same facet that the policy condition has been created
        IF (@object_set_facet_id <> (SELECT facet_id FROM msdb.dbo.syspolicy_conditions_internal WHERE condition_id = @condition_id))
        BEGIN
            -- TODO: RAISEERROR that specified object_set isn't created from the facet that the policy condition has been created from
            RAISERROR(N'specified object set does not match facet the policy condition was created off', -1, -1)
            RETURN(1) -- Failure
        END
    END

    DECLARE @policy_category_id INT
    SET @policy_category_id = NULL
    BEGIN TRANSACTION 

    DECLARE @old_policy_category_id INT
    SELECT @old_policy_category_id = policy_category_id 
        FROM syspolicy_policies 
        WHERE policy_id = @policy_id 

    IF ( (@policy_category IS NOT NULL and @policy_category != '') )
    BEGIN
        IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
        BEGIN
            RAISERROR(34015, -1, -1,@policy_category)
            RETURN(1) -- Failure
        END
        ELSE
            SELECT @policy_category_id = policy_category_id FROM msdb.dbo.syspolicy_policy_categories WHERE name = @policy_category
    END

        -- If the caller gave us an empty string for the
        -- @policy_category, then that means to remove the group.
    DECLARE @new_policy_category_id INT
        SELECT  @new_policy_category_id = @old_policy_category_id
    IF ( (@policy_category = '') )
                SELECT @new_policy_category_id = NULL
    ELSE IF (@policy_category_id IS NOT NULL)
                SELECT @new_policy_category_id = @policy_category_id

    UPDATE msdb.dbo.syspolicy_policies_internal
    SET 
        condition_id = ISNULL(@condition_id, condition_id),
        root_condition_id = CASE @root_condition_id WHEN -1 THEN root_condition_id ELSE @root_condition_id END,
        execution_mode = ISNULL(@execution_mode, execution_mode ),
        schedule_uid = @schedule_uid,
        policy_category_id = @new_policy_category_id, 
        description = ISNULL(@description, description),
        help_text = ISNULL(@help_text, help_text),
        help_link = ISNULL(@help_link, help_link),
        is_enabled = ISNULL(@is_enabled, is_enabled),
        object_set_id = CASE @object_set_id WHEN -1 THEN object_set_id ELSE @object_set_id END
    WHERE policy_id = @policy_id

    COMMIT TRANSACTION
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy] 
@name sysname = NULL,
@policy_id int = NULL
WITH EXECUTE AS OWNER
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    EXEC @retval = sp_syspolicy_verify_policy_identifiers @name, @policy_id OUTPUT
    IF (@retval <> 0)
        RETURN (1)

    DELETE msdb.dbo.syspolicy_policies_internal 
        WHERE policy_id = @policy_id

    RETURN (0)
END
GO


IF NOT EXISTS (SELECT * FROM sys.types where name = 'syspolicy_target_filters_type')
BEGIN
    PRINT 'Creating type [dbo].[syspolicy_target_filters_type]...'
    CREATE TYPE [dbo].[syspolicy_target_filters_type]
    AS
    TABLE (
        target_filter_id int,
        policy_id int,
        type sysname NOT NULL,
        filter nvarchar(max) NOT NULL,
        type_skeleton sysname NOT NULL
        )
END
GO

PRINT 'Creating function [dbo].[syspolicy_fn_get_bad_filters]...'
GO

-- This function returns filters that are not supported
-- It is used to prevent unsupported filters from being
-- created. It will only reject well formed filters, in 
-- other words it will not perform a full syntax check.
CREATE FUNCTION [dbo].[syspolicy_fn_get_bad_filters] (
    @inserted [dbo].[syspolicy_target_filters_type] READONLY
)
RETURNS TABLE
AS
    RETURN 
    (
        SELECT filter FROM @inserted 
        WHERE    
            -- do not accept filters for the next level 
            filter LIKE N'Server/%/%\[@%=%\]%' ESCAPE '\' AND 
            -- take out cases when the property contains the pattern
            filter NOT LIKE 'Server/%\[%\[%\]%\]%' ESCAPE '\'
    )
GO

---------------------------------------------------------------
-- Target Set object
---------------------------------------------------------------

IF OBJECT_ID ('[dbo].[syspolicy_target_sets_internal]') IS NULL
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_target_sets_internal]...'
    CREATE TABLE [dbo].[syspolicy_target_sets_internal] (
        target_set_id int NOT NULL IDENTITY(1,1),
        object_set_id int NOT NULL,
        type_skeleton nvarchar(440) NOT NULL,
        type sysname NOT NULL,
        enabled bit NOT NULL,
        -- TODO: Verify if the primary access method of this table is based on policy_id then perhaps the clustered intdex should be on the policy id?
        CONSTRAINT [PK_syspolicy_target_sets] PRIMARY KEY CLUSTERED (target_set_id),
        )
    ALTER TABLE [dbo].[syspolicy_target_sets_internal] 
        ADD CONSTRAINT [FK_syspolicy_target_sets_syspolicy_object_sets] FOREIGN KEY(object_set_id)
        REFERENCES [dbo].[syspolicy_object_sets_internal] (object_set_id)
        ON DELETE CASCADE
    
    CREATE UNIQUE INDEX [UX_syspolicy_target_sets] ON [dbo].[syspolicy_target_sets_internal](object_set_id, type_skeleton)
END
GO

PRINT 'Creating view [dbo].[syspolicy_target_sets]...'
GO
CREATE VIEW [dbo].[syspolicy_target_sets]
AS
    SELECT     
        target_set_id,
        object_set_id,
        type_skeleton,
        type,
        enabled
    FROM [dbo].[syspolicy_target_sets_internal]
GO

IF OBJECT_ID ('[dbo].[syspolicy_target_set_levels_internal]') IS NULL
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_target_set_levels_internal]...'
    CREATE TABLE [dbo].[syspolicy_target_set_levels_internal] (
        target_set_level_id int NOT NULL IDENTITY(1,1),
        target_set_id int NOT NULL,
        type_skeleton nvarchar(440) NOT NULL,
        condition_id int NULL,
        level_name sysname NOT NULL,
        CONSTRAINT [PK_syspolicy_target_set_levels_internal] PRIMARY KEY CLUSTERED (target_set_level_id),
        )
    ALTER TABLE [dbo].[syspolicy_target_set_levels_internal] 
        ADD CONSTRAINT [FK_syspolicy_levels_target_sets] FOREIGN KEY(target_set_id)
        REFERENCES [dbo].[syspolicy_target_sets_internal] (target_set_id)
        ON DELETE CASCADE
    ALTER TABLE [dbo].[syspolicy_target_set_levels_internal] 
        ADD CONSTRAINT [FK_syspolicy_levels_conditions] FOREIGN KEY(condition_id)
        REFERENCES [dbo].[syspolicy_conditions_internal] (condition_id)
    
    CREATE UNIQUE INDEX [UX_syspolicy_levels] ON [dbo].[syspolicy_target_sets_internal](target_set_id, type_skeleton)
END
GO

PRINT 'Creating view [dbo].[syspolicy_target_set_levels]...'
GO
CREATE VIEW [dbo].[syspolicy_target_set_levels]
AS
    SELECT     
        target_set_level_id,
        target_set_id,
        type_skeleton,
        condition_id,
        level_name
    FROM [dbo].[syspolicy_target_set_levels_internal]
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_target_set] 
@object_set_id int = NULL,
@object_set_name sysname = NULL,
@type_skeleton nvarchar(max),
@type sysname,
@enabled bit,
@target_set_id int OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    EXEC @retval = dbo.sp_syspolicy_verify_object_set_identifiers @name = @object_set_name OUTPUT, @object_set_id = @object_set_id OUTPUT
    if( @retval <> 0)
        RETURN(1)
    
    INSERT INTO msdb.[dbo].[syspolicy_target_sets_internal]
                                        (object_set_id,
                                        type_skeleton,
                                        type,
                                        enabled)
    VALUES                            
                                        (@object_set_id, 
                                        @type_skeleton,
                                        @type,
                                        @enabled)

    SELECT @retval = @@error
    SET @target_set_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_target_set]
@target_set_id int,
@enabled bit
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	UPDATE [msdb].[dbo].[syspolicy_target_sets_internal]
	SET
		enabled = @enabled
	WHERE
		target_set_id = @target_set_id
	
	IF (@@ROWCOUNT = 0)
	BEGIN
		DECLARE @target_set_id_as_char VARCHAR(36)
		SELECT @target_set_id_as_char = CONVERT(VARCHAR(36), @target_set_id)
		RAISERROR(14262, -1, -1, '@target_set_id', @target_set_id_as_char)
		RETURN (1)
	END

    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_target_set]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_target_set] 
@target_set_id int
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DELETE msdb.[dbo].[syspolicy_target_sets_internal] 
		WHERE target_set_id = @target_set_id
	
	IF (@@ROWCOUNT = 0)
	BEGIN
		DECLARE @target_set_id_as_char VARCHAR(36)
		SELECT @target_set_id_as_char = CONVERT(VARCHAR(36), @target_set_id)
		RAISERROR(14262, -1, -1, '@target_set_id', @target_set_id_as_char)
		RETURN (1)
	END

    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_target_set_level]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_target_set_level] 
@target_set_id int,
@type_skeleton nvarchar(max),
@condition_id int = NULL,
@condition_name sysname = NULL,
@level_name sysname,
@target_set_level_id int OUTPUT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval              INT

    IF NOT EXISTS (SELECT * FROM syspolicy_target_sets WHERE target_set_id = @target_set_id)
            RETURN (1)

    IF (@condition_name = '')
        SET @condition_name = NULL

    IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
    BEGIN
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
        IF (@retval <> 0)
            RETURN (1)
    END

    
    INSERT INTO msdb.[dbo].[syspolicy_target_set_levels_internal]
                                        (target_set_id,
                                        type_skeleton,
                                        condition_id,
                                        level_name)
    VALUES                            
                                        (@target_set_id,
                                        @type_skeleton,
                                        @condition_id,
                                        @level_name)

    SELECT @retval = @@error
    SET @target_set_level_id = SCOPE_IDENTITY()
    RETURN(@retval)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_target_set_level]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_target_set_level] 
@target_set_id int,
@type_skeleton nvarchar(max),
@condition_id int = NULL,
@condition_name sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @retval int

    IF @condition_name = '' SET @condition_name = NULL

    IF(@condition_id IS NOT NULL or @condition_name IS NOT NULL)
    BEGIN
        EXEC @retval = msdb.dbo.sp_syspolicy_verify_condition_identifiers @condition_name = @condition_name OUTPUT, @condition_id = @condition_id OUTPUT
        IF (@retval <> 0)
            RETURN (1)
    END

    UPDATE msdb.[dbo].[syspolicy_target_set_levels_internal] 
        SET condition_id = @condition_id
        WHERE target_set_id = @target_set_id AND type_skeleton = @type_skeleton
    
    IF (@@ROWCOUNT = 0)
    BEGIN
        DECLARE @id nvarchar(max)
        SET @id = '@target_set_id='+LTRIM(STR(@target_set_id))+' @type_skeleton='''+@type_skeleton+''''
        RAISERROR(14262, -1, -1, 'Target Set Level', @id)
        RETURN (1)
    END

    RETURN (0)
END
GO

PRINT 'Creating function [dbo].[syspolicy_fn_eventing_filter]'
GO

CREATE FUNCTION [dbo].[syspolicy_fn_eventing_filter] (@target_set_id INT)
RETURNS INT
AS
BEGIN
    DECLARE @cnt int, @level sysname, @condition_id int, @ret int

    SELECT @cnt = count(*) FROM msdb.dbo.syspolicy_target_set_levels 
        WHERE target_set_id = @target_set_id AND condition_id IS NOT NULL
    IF @cnt = 0 
        RETURN 1
    ELSE IF @cnt > 1
        RETURN 0
    ELSE
        BEGIN
        SELECT @level = level_name, @condition_id = condition_id FROM msdb.dbo.syspolicy_target_set_levels 
            WHERE target_set_id = @target_set_id AND condition_id IS NOT NULL
        IF @level != 'Database'
            RETURN 0

        SELECT @ret = is_name_condition 
        FROM msdb.dbo.syspolicy_conditions    
        WHERE condition_id = @condition_id
        END

    RETURN @ret
END
GO

PRINT 'Creating function [dbo].[syspolicy_fn_filter_complete]'
GO

CREATE FUNCTION [dbo].[syspolicy_fn_filter_complete] (@target_set_id INT)
RETURNS INT
AS
BEGIN
    DECLARE @target_set_skeleton nvarchar(max), @skeleton nvarchar(max), @level sysname, @dummy nvarchar(max), @ret int, 
            @i int, @p int
    
    SELECT @target_set_skeleton = type_skeleton, @i=0, @p=CHARINDEX('/',type_skeleton)
        FROM msdb.dbo.syspolicy_target_sets 
        WHERE target_set_id = @target_set_id

    IF @@ROWCOUNT != 1 RETURN 0
    
    IF @target_set_skeleton = 'Server' RETURN 1    

    -- Count the number of levels in the skeleton past the root
    WHILE (@p <> 0)
        BEGIN
            SET @i = @i + 1
        SET @p = CHARINDEX('/', @target_set_skeleton, @p + 1)
        END

    -- Compare the number of levels in the skeleton with those in TSL
    IF (@i = (SELECT COUNT(*) FROM msdb.dbo.syspolicy_target_set_levels 
             WHERE target_set_id = @target_set_id))
        RETURN 1

    RETURN 0
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_insert_target_set_level_trigger] on [dbo].[syspolicy_target_set_levels_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_insert_target_set_level_trigger] 
    ON [dbo].[syspolicy_target_set_levels_internal]
FOR INSERT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

    DECLARE @update_notifications INT
    DECLARE @update_ddl_trigger   INT

    SET @update_notifications = 0
    SET @update_ddl_trigger = 0

    SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
        FROM inserted i
        JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
        JOIN msdb.dbo.syspolicy_object_sets_internal os ON (s.object_set_id = os.object_set_id)
        JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)    
        WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
            ((p.execution_mode & 3) > 0 AND p.is_enabled = 1 AND 1 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))

    IF (@update_ddl_trigger > 0)
        EXEC sys.sp_syspolicy_update_ddl_trigger 

    IF    (@update_notifications > 0)    
        EXEC sys.sp_syspolicy_update_event_notification 

    DECLARE @row_count int    

    SELECT @row_count = count(*) 
    FROM inserted i 
    INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = i.target_set_id
    INNER JOIN dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
    INNER JOIN syspolicy_policies p ON os.object_set_id = p.object_set_id
    INNER JOIN syspolicy_conditions c on p.condition_id = c.condition_id
    WHERE    p.is_enabled != 0 AND
            p.execution_mode != 4 AND
            (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]') OR
            1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]') )
    OPTION (FORCE ORDER)

    IF (@row_count > 0)
    BEGIN
        RAISERROR(34017, -1, -1) 
        ROLLBACK TRANSACTION
    END
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_update_target_set_level_trigger] on [dbo].[syspolicy_target_set_levels_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_update_target_set_level_trigger] ON [dbo].[syspolicy_target_set_levels_internal]
FOR UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

    DECLARE @update_notifications INT
    DECLARE @update_ddl_trigger   INT

    SET @update_notifications = 0
    SET @update_ddl_trigger = 0

    SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
        FROM inserted i
        JOIN dbo.syspolicy_target_sets s ON (i.target_set_id = s.target_set_id)
        JOIN msdb.dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
        JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)    
        WHERE 1 = dbo.syspolicy_fn_filter_complete (i.target_set_id) AND
            ((p.execution_mode & 3) > 0 AND p.is_enabled = 1 AND 1 = dbo.syspolicy_fn_eventing_filter (i.target_set_id))

    IF (@update_ddl_trigger > 0)
        EXEC sys.sp_syspolicy_update_ddl_trigger 

    IF    (@update_notifications > 0)    
        EXEC sys.sp_syspolicy_update_event_notification 


    IF UPDATE(condition_id)
    BEGIN
        DECLARE @row_count int    

        SELECT @row_count = count(*) 
        FROM inserted i 
        INNER JOIN dbo.syspolicy_target_sets s ON s.target_set_id = i.target_set_id
        INNER JOIN dbo.syspolicy_object_sets os ON s.object_set_id = os.object_set_id
        INNER JOIN syspolicy_policies p ON os.object_set_id = p.object_set_id
        INNER JOIN syspolicy_conditions c on p.condition_id = c.condition_id
        WHERE    p.is_enabled != 0 AND
                p.execution_mode != 4 AND
                (1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteSql"]') OR
                1 = CONVERT(xml, c.expression).exist('//FunctionType/text()[.="ExecuteWql"]') )
        OPTION (FORCE ORDER)

        IF (@row_count > 0)
        BEGIN
            RAISERROR(34017, -1, -1) 
            ROLLBACK TRANSACTION
        END
    END

END
GO

PRINT 'Creating trigger [dbo].[syspolicy_insert_target_set_trigger] on [dbo].[syspolicy_target_sets_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_insert_target_set_trigger] 
    ON [dbo].[syspolicy_target_sets_internal]
FOR INSERT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

    DECLARE @update_notifications INT
    DECLARE @update_ddl_trigger   INT

    SET @update_notifications = 0
    SET @update_ddl_trigger = 0

    -- Only need to check Server TargetSets, as they don't have levels
    SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
        FROM inserted i
        JOIN msdb.dbo.syspolicy_object_sets_internal os ON i.object_set_id = os.object_set_id
        JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)    
        WHERE i.type = 'SERVER' AND ((p.execution_mode & 3) > 0 AND p.is_enabled = 1)

    IF (@update_ddl_trigger > 0)
        EXEC sys.sp_syspolicy_update_ddl_trigger 

    IF    (@update_notifications > 0)    
        EXEC sys.sp_syspolicy_update_event_notification 
END
GO

PRINT 'Creating trigger [dbo].[syspolicy_delete_target_set_trigger] on [dbo].[syspolicy_target_sets_internal]'
GO

CREATE TRIGGER [dbo].[syspolicy_delete_target_set_trigger] ON [dbo].[syspolicy_target_sets_internal]
FOR DELETE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

    DECLARE @update_notifications INT
    DECLARE @update_ddl_trigger   INT

    SET @update_notifications = 0
    SET @update_ddl_trigger = 0

    -- If this is cascade delete, there will be no policies to join
    SELECT @update_notifications = SUM (p.execution_mode & 2), @update_ddl_trigger = SUM (p.execution_mode & 1)
        FROM deleted d
        JOIN msdb.dbo.syspolicy_object_sets_internal os ON d.object_set_id = os.object_set_id
        JOIN msdb.dbo.syspolicy_policies p ON (os.object_set_id = p.object_set_id)    
        WHERE ((p.execution_mode & 3) > 0 AND p.is_enabled = 1)

    IF (@update_ddl_trigger > 0)
        EXEC sys.sp_syspolicy_update_ddl_trigger 

    IF    (@update_notifications > 0)    
        EXEC sys.sp_syspolicy_update_event_notification 
END
GO


---------------------------------------------------------------
-- Policy category subscription object
---------------------------------------------------------------

IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_category_subscriptions_internal')
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_policy_category_subscriptions_internal]...';
    CREATE TABLE [dbo].[syspolicy_policy_category_subscriptions_internal] (
        policy_category_subscription_id int IDENTITY(1,1),
        target_type sysname NOT NULL,
        target_object sysname NOT NULL, 
        policy_category_id int NOT NULL,
        CONSTRAINT [PK_syspolicy_policy_category_subscriptions] PRIMARY KEY CLUSTERED (policy_category_subscription_id ASC)
        );

    CREATE UNIQUE INDEX [UX_syspolicy_policy_category_subscriptions] ON [dbo].[syspolicy_policy_category_subscriptions_internal](policy_category_id, target_object, target_type)

    ALTER TABLE [dbo].[syspolicy_policy_category_subscriptions_internal] 
        ADD CONSTRAINT [FK_syspolicy_policy_category_subscriptions_syspolicy_policy_categories] FOREIGN KEY(policy_category_id)
        REFERENCES [dbo].[syspolicy_policy_categories_internal] (policy_category_id)
        ON DELETE CASCADE;
END
GO

PRINT 'Creating view [dbo].[syspolicy_policy_category_subscriptions]...'
GO
CREATE VIEW [dbo].[syspolicy_policy_category_subscriptions]
AS
    SELECT     
        policy_category_subscription_id,
        target_type,
        target_object,
        policy_category_id
    FROM [dbo].[syspolicy_policy_category_subscriptions_internal]
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_add_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_add_policy_category_subscription] 
    @target_type sysname,
    @target_object sysname,
    @policy_category sysname,
    @policy_category_subscription_id int = NULL OUTPUT
WITH EXECUTE AS OWNER
AS
BEGIN
    DECLARE @retval int    

 IF(@target_type IS NOT NULL)
	BEGIN
		IF(@target_type <> 'DATABASE')
		BEGIN
			RAISERROR(34018,-1,-1,@target_type);
			RETURN(1)
		END
	END


 IF(NOT EXISTS(SELECT * FROM sys.databases WHERE name=@target_object))
	BEGIN
		RAISERROR(34019,-1,-1,@target_object);
		RETURN(1)
	END

    -- convert category_name into id if needed
    DECLARE @policy_category_id INT
    BEGIN TRANSACTION 
    IF ( (@policy_category IS NOT NULL AND @policy_category != '') )
    BEGIN 
        IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
        BEGIN
            INSERT INTO syspolicy_policy_categories_internal(name) VALUES (@policy_category)
            SELECT @policy_category_id = SCOPE_IDENTITY()
        END
        ELSE
            SELECT @policy_category_id = policy_category_id FROM syspolicy_policy_categories WHERE name = @policy_category
    END
    
    INSERT INTO msdb.[dbo].[syspolicy_policy_category_subscriptions_internal]
                                            (target_type, 
                                            target_object,
                                            policy_category_id)
        VALUES                            
                                            (@target_type, 
                                            @target_object, 
                                            @policy_category_id)

    SELECT @retval = @@error
    SET @policy_category_subscription_id = SCOPE_IDENTITY()

    COMMIT TRANSACTION
    RETURN(@retval)

END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_update_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_update_policy_category_subscription] 
@policy_category_subscription_id int,
@target_type sysname = NULL,
@target_object sysname = NULL,
@policy_category sysname = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	-- Turn [nullable] empty string parameters into NULLs
	IF @target_type = ''      SELECT @target_type = NULL
	IF @target_object = ''    SELECT @target_object = NULL
	IF @policy_category = ''  SELECT @policy_category = NULL

    IF(@target_type IS NOT NULL)
	BEGIN
		IF(LOWER(@target_type) <> 'database')
		BEGIN
			RAISERROR(34018,-1,-1,@target_type);
			RETURN(1)
		END
	END
	
	IF(@target_object IS NOT NULL AND NOT EXISTS(SELECT * FROM sys.databases WHERE name=@target_object))
	BEGIN
		RAISERROR(34019,-1,-1,@target_object);
		RETURN(1)
	END

    DECLARE @policy_category_id INT
    SET @policy_category_id = NULL
    BEGIN TRANSACTION 

    DECLARE @old_policy_category_id INT
    SET @old_policy_category_id = NULL

    IF ( (@policy_category IS NOT NULL) )
    BEGIN 
        IF NOT EXISTS (SELECT * from syspolicy_policy_categories WHERE name = @policy_category)
        BEGIN
            -- add a new policy category
            INSERT INTO syspolicy_policy_categories_internal(name) VALUES (@policy_category)
            SELECT @policy_category_id = SCOPE_IDENTITY()

            SELECT @old_policy_category_id = policy_category_id 
                FROM syspolicy_policy_category_subscriptions 
                WHERE policy_category_subscription_id = @policy_category_subscription_id 
        END
        ELSE
            SELECT @policy_category_id = policy_category_id FROM syspolicy_policy_categories WHERE name = @policy_category
    END
    
    DECLARE @group_usage_count INT
    SELECT @group_usage_count = COUNT(*) 
        FROM syspolicy_policy_category_subscriptions  
        WHERE policy_category_id = @old_policy_category_id

    SELECT @group_usage_count = @group_usage_count + COUNT(*) 
        FROM syspolicy_policies  
        WHERE policy_category_id = @old_policy_category_id

    UPDATE msdb.[dbo].[syspolicy_policy_category_subscriptions_internal] 
        SET
            target_type            = ISNULL(@target_type, target_type),
            target_object       = ISNULL(@target_object, target_object),
            policy_category_id        = ISNULL(@policy_category_id, policy_category_id)
        WHERE policy_category_subscription_id = @policy_category_subscription_id

    IF (@@ROWCOUNT = 0)
    BEGIN
        DECLARE @policy_category_subscription_id_as_char VARCHAR(36)
        SELECT @policy_category_subscription_id_as_char = CONVERT(VARCHAR(36), @policy_category_subscription_id)
        RAISERROR(14262, -1, -1, '@policy_category_subscription_id', @policy_category_subscription_id_as_char)
        ROLLBACK TRANSACTION
        RETURN(1) -- Failure
    END

    -- delete the old entry if it was used only by this policy
    DELETE syspolicy_policy_categories_internal WHERE 
        policy_category_id = @old_policy_category_id
        AND 1 = @group_usage_count

    COMMIT TRANSACTION
    RETURN (0)
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_category_subscription]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_delete_policy_category_subscription] 
@policy_category_subscription_id int
WITH EXECUTE AS OWNER
AS
BEGIN
    DECLARE @old_policy_category_id INT
    SELECT @old_policy_category_id = policy_category_id 
        FROM dbo.syspolicy_policy_category_subscriptions 
        WHERE policy_category_subscription_id = @policy_category_subscription_id

    DECLARE @group_usage_count INT
    SELECT @group_usage_count = COUNT(name) 
        FROM syspolicy_policies pd 
        WHERE pd.policy_category_id = @old_policy_category_id

    DECLARE @subscription_group_usage_count INT
    SELECT @subscription_group_usage_count = COUNT(*) 
        FROM syspolicy_policy_category_subscriptions  
        WHERE policy_category_id = @old_policy_category_id

    SELECT @group_usage_count = @group_usage_count + @subscription_group_usage_count

    DELETE msdb.dbo.syspolicy_policy_category_subscriptions_internal 
        WHERE policy_category_subscription_id = @policy_category_subscription_id

    IF (@@ROWCOUNT = 0)
    BEGIN
        DECLARE @policy_category_subscription_id_as_char VARCHAR(36)
        SELECT @policy_category_subscription_id_as_char = CONVERT(VARCHAR(36), @policy_category_subscription_id)
        RAISERROR(14262, -1, -1, '@policy_category_subscription_id', @policy_category_subscription_id_as_char)
        RETURN(1) -- Failure
    END

    RETURN (0)
END
GO

GO
IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_system_health_state_internal')
BEGIN
	PRINT 'Creating table [dbo].[syspolicy_system_health_state_internal]...'
	CREATE TABLE [dbo].[syspolicy_system_health_state_internal](
			health_state_id bigint IDENTITY PRIMARY KEY CLUSTERED,
			policy_id int NOT NULL REFERENCES [dbo].[syspolicy_policies_internal],
			last_run_date datetime NOT NULL, 
			target_query_expression_with_id nvarchar(400) NOT NULL, 
			target_query_expression nvarchar(max) NOT NULL, 
			result bit NOT NULL);
	CREATE INDEX IX_syspolicy_system_health_state_internal_policy_id ON 
		[dbo].[syspolicy_system_health_state_internal](policy_id);
	CREATE INDEX IX_syspolicy_system_health_state_internal_target_query_expression_with_id ON
		[dbo].[syspolicy_system_health_state_internal](target_query_expression_with_id);
END
GO

CREATE VIEW [dbo].[syspolicy_system_health_state]
AS
    SELECT 
        health_state_id,
        policy_id,
        last_run_date,
        target_query_expression_with_id,
        target_query_expression,
        result
    FROM [dbo].[syspolicy_system_health_state_internal]
GO

IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_execution_history_internal')
BEGIN
	PRINT 'Creating table [dbo].[syspolicy_policy_execution_history_internal]...';
	CREATE TABLE syspolicy_policy_execution_history_internal (
		history_id bigint IDENTITY PRIMARY KEY CLUSTERED,
		policy_id int NOT NULL REFERENCES syspolicy_policies_internal,
		start_date datetime NOT NULL DEFAULT (GETDATE()),
		end_date datetime NULL,
		result bit NOT NULL DEFAULT (0),
		is_full_run bit NOT NULL DEFAULT (1),
		exception_message nvarchar(max) NULL,
		exception nvarchar(max) NULL
	);
	CREATE INDEX IX_syspolicy_policy_execution_history_internal_end_date_policy_id 
		ON [dbo].[syspolicy_policy_execution_history_internal](policy_id, end_date);
	CREATE INDEX IX_syspolicy_policy_execution_history_internal_policy_id 
		ON [dbo].[syspolicy_policy_execution_history_internal](policy_id);
END

PRINT 'Creating trigger [syspolicy_update_system_health_state]...'
GO
CREATE TRIGGER [syspolicy_update_system_health_state] ON [dbo].[syspolicy_policy_execution_history_internal]
AFTER UPDATE
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

    -- if the entire policy has been checked delete all entries 
    -- regarding that policy
    DELETE FROM [dbo].[syspolicy_system_health_state_internal] 
        WHERE policy_id in (SELECT policy_id FROM inserted WHERE is_full_run = 1)

    -- Note: in the queries below new records are added only for
    -- policies that are enabled for automation

    -- if the policy is evaluated against a single target
    -- delete the old entry
    DELETE FROM [dbo].[syspolicy_system_health_state_internal] 
        WHERE policy_id in 
            (SELECT i.policy_id FROM inserted i WHERE i.is_full_run = 0) AND
                target_query_expression_with_id in (SELECT target_query_expression_with_id 
                                                    FROM [dbo].[syspolicy_policy_execution_history_details_internal] d 
                                                    INNER JOIN inserted i2 ON i2.history_id = d.history_id 
                                                    WHERE i2.is_full_run = 0)


    -- insert the detail rows, but only for failures
    -- this is done both for the full runs and for the partial runs
    -- we will not insert anything if this is a ghost record, i.e. 
    -- target_query_expression_with_id is null 
    -- this will happen when we log prevent policies
    INSERT INTO [dbo].[syspolicy_system_health_state_internal] 
        (policy_id, last_run_date, target_query_expression_with_id, target_query_expression, result)
    SELECT i.policy_id, d.execution_date, d.target_query_expression_with_id, d.target_query_expression, d.result
        FROM inserted i 
        INNER JOIN [dbo].[syspolicy_policy_execution_history_details_internal] d on i.history_id = d.history_id
        INNER JOIN [dbo].[syspolicy_policies] p on i.policy_id = p.policy_id
        WHERE d.result = 0 AND p.is_enabled = 1 AND d.target_query_expression_with_id != N''
        
    -- delete all the success detail rows with no expression
    -- these are rows inserted so that we can update the system health state
    -- make an exception if the global switch says we should keep those records
    IF( 0 = (SELECT ISNULL(convert(bit, current_value), 0) FROM msdb.dbo.syspolicy_configuration WHERE name = 'LogOnSuccess'))
    BEGIN
        DELETE FROM d
        FROM [dbo].[syspolicy_policy_execution_history_details_internal] d
        INNER JOIN inserted i ON i.history_id = d.history_id
            WHERE d.result_detail = N''
    END
END
GO

CREATE VIEW [dbo].[syspolicy_policy_execution_history]
AS
    SELECT 
        history_id,
        policy_id,
        start_date,
        end_date,
        result,
        exception_message,
        exception
    FROM [dbo].[syspolicy_policy_execution_history_internal]
GO

IF NOT EXISTS (SELECT * FROM sys.tables where name = 'syspolicy_policy_execution_history_details_internal')
BEGIN
	PRINT 'Creating table [dbo].[syspolicy_policy_execution_history_details_internal]...';
	CREATE TABLE syspolicy_policy_execution_history_details_internal (
	detail_id bigint IDENTITY PRIMARY KEY CLUSTERED,
	history_id bigint NOT NULL REFERENCES syspolicy_policy_execution_history_internal ON DELETE CASCADE,
	target_query_expression nvarchar(4000) NOT NULL,
	target_query_expression_with_id nvarchar(4000) NOT NULL,
	execution_date datetime NOT NULL DEFAULT (GETDATE()),
	result bit NOT NULL,
	result_detail nvarchar(max) NULL, 
	exception_message nvarchar(max) NULL,
	exception nvarchar(max) NULL
	);
	CREATE INDEX IX_syspolicy_policy_execution_history_details_internal_result ON
		[dbo].[syspolicy_policy_execution_history_details_internal](result);
END
GO

CREATE VIEW [dbo].[syspolicy_policy_execution_history_details]
AS
    SELECT 
        detail_id,
        history_id,
        target_query_expression,
        execution_date,
        result,
        result_detail,
        exception_message,
        exception
    FROM [dbo].[syspolicy_policy_execution_history_details_internal]
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_start]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_start] 
    @policy_id int,
    @is_full_run bit,
    @history_id bigint OUTPUT 
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END
    DECLARE @ret int

    SET @history_id = 0

    EXEC @ret = dbo.sp_syspolicy_verify_policy_identifiers NULL, @policy_id
    IF @ret <> 0 RETURN -1

    INSERT syspolicy_policy_execution_history_internal (policy_id, is_full_run) VALUES (@policy_id, @is_full_run) 
    SET @history_id = SCOPE_IDENTITY ()
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_end]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_end] 
    @history_id bigint, 
    @result bit,
    @exception_message nvarchar(max) = NULL,
    @exception nvarchar(max) = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    UPDATE syspolicy_policy_execution_history_internal 
      SET result = @result,
          end_date = GETDATE(),
          exception_message = @exception_message,
          exception = @exception
      WHERE history_id = @history_id
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_log_policy_execution_detail]...'
GO
CREATE PROC [dbo].[sp_syspolicy_log_policy_execution_detail] 
 @history_id bigint, 
 @target_query_expression nvarchar(4000), 
 @target_query_expression_with_id nvarchar(4000), 
 @result bit, 
 @result_detail nvarchar(max),
 @exception_message nvarchar(max) = NULL,
 @exception nvarchar(max) = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole', 0
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END
    BEGIN TRANSACTION
    DECLARE @is_valid_entry INT
    -- take an update lock on this table first to prevent deadlock
    SELECT @is_valid_entry = count(*) FROM syspolicy_policy_execution_history_internal
        WITH (UPDLOCK) 
        WHERE history_id = @history_id

    INSERT syspolicy_policy_execution_history_details_internal (
                                history_id, 
                                target_query_expression, 
                                target_query_expression_with_id, 
                                result, 
                                result_detail,
                                exception_message,
                                exception) 
                        VALUES (
                                @history_id, 
                                @target_query_expression, 
                                @target_query_expression_with_id, 
                                @result, 
                                @result_detail,
                                @exception_message,
                                @exception) 
    IF( @@TRANCOUNT > 0)
        COMMIT
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_delete_policy_execution_history]...'
GO
CREATE PROC [dbo].[sp_syspolicy_delete_policy_execution_history] 
 @policy_id int,
 @oldest_date datetime
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    IF @oldest_date IS NULL
        BEGIN
        IF (@policy_id IS NULL)
            DELETE syspolicy_policy_execution_history_internal
        ELSE
            DELETE syspolicy_policy_execution_history_internal WHERE policy_id = @policy_id
        END
    ELSE
        BEGIN
        IF (@policy_id IS NULL)
            DELETE syspolicy_policy_execution_history_internal WHERE start_date < @oldest_date
        ELSE
            DELETE syspolicy_policy_execution_history_internal WHERE policy_id = @policy_id AND start_date < @oldest_date
        END
END
GO




-----------------------------------------------------------
-- event processing
-----------------------------------------------------------

PRINT 'Creating function [dbo].[syspolicy_fn_get_type_name]...'
GO
CREATE FUNCTION [dbo].[syspolicy_fn_get_type_name](@event_type_name sysname)
RETURNS sysname
AS
BEGIN
    RETURN 
    (CASE LOWER(@event_type_name)
        WHEN 'procedure' THEN 'StoredProcedure'
        WHEN 'function' THEN 'UserDefinedFunction'
        WHEN 'type' THEN 'UserDefinedType'
        WHEN 'sql user' THEN 'User'
        WHEN 'certificate user' THEN 'User'
        WHEN 'asymmetric key user' THEN 'User'
        WHEN 'windows user' THEN 'User'
        WHEN 'group user' THEN 'User'
        WHEN 'application role' THEN 'ApplicationRole'
        ELSE UPPER(SUBSTRING(@event_type_name, 1,1)) + LOWER(SUBSTRING(@event_type_name, 2,LEN(@event_type_name)))
    END)
END
GO

IF OBJECT_ID ('[dbo].[syspolicy_execution_internal]') IS NULL
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_execution_internal]...'
    CREATE TABLE [dbo].[syspolicy_execution_internal] (
        policy_id int,
        synchronous bit,
        event_data xml)
END
GO

IF OBJECT_ID ('[dbo].[syspolicy_execution_trigger]') IS NOT NULL
BEGIN
    DROP TRIGGER [dbo].[syspolicy_execution_trigger] 
END
GO
CREATE TRIGGER [dbo].[syspolicy_execution_trigger] ON [dbo].[syspolicy_execution_internal]
INSTEAD OF INSERT
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN;
	END

	IF NOT EXISTS (SELECT * FROM inserted)
		RETURN

    DECLARE @policy_id int
    DECLARE @synchronous bit
    DECLARE @event_data xml
    DECLARE affected_policies CURSOR LOCAL FOR 
        SELECT policy_id, synchronous, event_data FROM inserted
    
    OPEN affected_policies
    FETCH NEXT FROM affected_policies INTO @policy_id, @synchronous, @event_data
    DECLARE @err int
    SET @err = 0
    WHILE (@@FETCH_STATUS = 0 AND (@synchronous = 0 OR @err = 0)) 
    BEGIN
        DECLARE @pol_name sysname
        SELECT @pol_name = p.name
            FROM dbo.syspolicy_policies p 
            WHERE p.policy_id = @policy_id

        IF (@synchronous = 0)
        BEGIN
            -- trace what policy is processing this event
            DECLARE @msg nvarchar(1000)
            SET @msg = N'Policy ''' + @pol_name + ''' was activated by an event.'
            RAISERROR(@msg, 1, 1) with log
        END

        -- execute the policy
        EXEC @err = msdb.sys.sp_syspolicy_execute_policy @policy_name =@pol_name, @event_data = @event_data, @synchronous = @synchronous
    
        -- move to the next policy if we're checking the policy
        -- or if we are in enforce mode and we haven't failed
        IF( @synchronous = 0 OR @err = 0)
            FETCH NEXT FROM affected_policies INTO @policy_id, @synchronous, @event_data
    END

    CLOSE affected_policies
    DEALLOCATE affected_policies

END
GO
    

PRINT 'Creating procedure [dbo].[sp_syspolicy_dispatch_event]...'
GO
-- These settings are necessary to read XML.
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
SET ARITHABORT ON
SET CONCAT_NULL_YIELDS_NULL ON
SET NUMERIC_ROUNDABORT OFF
SET QUOTED_IDENTIFIER ON
GO

-- procedure that processes an event and decides 
-- what binding should handle it
CREATE PROCEDURE [dbo].[sp_syspolicy_dispatch_event]  @event_data xml, @synchronous bit
AS
BEGIN
	-- disable these as the caller may not have SHOWPLAN permission
	SET STATISTICS XML OFF
	SET STATISTICS PROFILE OFF

	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	IF ( @synchronous = 0)
		PRINT CONVERT(nvarchar(max), @event_data)
	DECLARE @event_type sysname
	DECLARE @object_type sysname
	DECLARE @database sysname
	DECLARE @mode int
	DECLARE @filter_expression nvarchar(4000)
	DECLARE @filter_expression_skeleton nvarchar(4000)

    SET @mode = (case @synchronous when 1 then 1 else 2 end)

    -- These settings are necessary to read XML.
    SET ANSI_NULLS ON
    SET ANSI_PADDING ON
    SET ANSI_WARNINGS ON
    SET ARITHABORT ON
    SET CONCAT_NULL_YIELDS_NULL ON
    SET NUMERIC_ROUNDABORT OFF
    SET QUOTED_IDENTIFIER ON

    SET NOCOUNT ON 

    SELECT 
        @event_type = T.c.value('(EventType/text())[1]', 'sysname')
        , @database = T.c.value('(DatabaseName/text())[1]', 'sysname')
        , @object_type = T.c.value('(ObjectType/text())[1]', 'sysname')
    FROM   @event_data.nodes('/EVENT_INSTANCE') T(c)
    
    -- we are going to ignore events that affect subobjects
    IF  (@event_type = N'ALTER_DATABASE' AND 
        1 = @event_data.exist('EVENT_INSTANCE/AlterDatabaseActionList')) OR
        (@event_type = N'ALTER_TABLE' AND 
        1 = @event_data.exist('EVENT_INSTANCE/AlterTableActionList'))
    BEGIN
        RETURN;
    END

    -- convert trace numerical objecttypes to string
    IF (ISNUMERIC(@object_type) = 1)
        select @object_type = name from master.dbo.spt_values where type = 'EOB' and number = @object_type

    -- these events do not have ObjectType and ObjectName
    IF ((@object_type IS NULL) AND @event_type IN ('CREATE_DATABASE', 'DROP_DATABASE', 'ALTER_DATABASE'))
    BEGIN
        SET @object_type = 'DATABASE'
    END

    INSERT msdb.dbo.syspolicy_execution_internal
        SELECT p.policy_id , @synchronous, @event_data
        FROM dbo.syspolicy_policies p
        INNER JOIN dbo.syspolicy_conditions_internal c ON c.condition_id = p.condition_id
        INNER JOIN dbo.syspolicy_facet_events fe ON c.facet_id = fe.management_facet_id
        INNER JOIN dbo.syspolicy_target_sets ts ON ts.object_set_id = p.object_set_id AND ts.type = fe.target_type
        LEFT JOIN dbo.syspolicy_policy_category_subscriptions pgs ON pgs.policy_category_id = p.policy_category_id
        LEFT JOIN dbo.syspolicy_target_set_levels tsl on tsl.target_set_id = ts.target_set_id AND tsl.level_name = 'Database'
        LEFT JOIN dbo.syspolicy_conditions_internal lc ON lc.condition_id = tsl.condition_id
        LEFT JOIN dbo.syspolicy_policy_categories cat on p.policy_category_id = cat.policy_category_id
        WHERE fe.event_name=@event_type AND 
            p.is_enabled = 1 AND
            fe.target_type_alias = @object_type AND
            -- 1 means Enforce, 2 means CheckOnChange
            (p.execution_mode & @mode) = @mode AND
            ((p.policy_category_id IS NULL) OR (cat.mandate_database_subscriptions = 1) OR ( ts.type_skeleton NOT LIKE 'Server/Database%') OR (@database IS NOT NULL AND pgs.target_object = @database)) AND
            ((@database IS NULL) OR 
             (@database IS NOT NULL AND 
              (tsl.condition_id IS NULL OR 
               (tsl.condition_id IS NOT NULL AND 
                ((lc.is_name_condition=1 AND @database = lc.obj_name) OR
                 (lc.is_name_condition=2 AND @database LIKE lc.obj_name) OR
                 (lc.is_name_condition=3 AND @database != lc.obj_name) OR
                 (lc.is_name_condition=4 AND @database NOT LIKE lc.obj_name))
               )
              )
             )
            ) 

    -- NOTE: if we haven't subscribed via an Endpoint facet on those events 
    -- we know for sure they will not be processed by the ServerAreaFacet policies 
    -- because syspolicy_facet_events expects @target_type to be SERVER
    -- so the filter will leave them out, and we are going to generate a fake 
    -- event to make those policies run
    IF( @synchronous = 0 AND 
        (@event_type IN ('ALTER_ENDPOINT', 'CREATE_ENDPOINT', 'DROP_ENDPOINT')))
    BEGIN
        DECLARE @fake_event_data xml
        SET @fake_event_data = CONVERT(xml, '<EVENT_INSTANCE><EventType>SAC_ENDPOINT_CHANGE</EventType><ObjectType>21075</ObjectType><ObjectName/><DatabaseName>master</DatabaseName></EVENT_INSTANCE>')
        
        EXEC [dbo].[sp_syspolicy_dispatch_event]  @event_data = @fake_event_data, @synchronous = 0
    END
            
END              
GO 

/* 
 * Asynchronous events collection via event notifications
 */

PRINT N'Dropping service [syspolicy_event_listener]...'
GO
IF EXISTS (SELECT * FROM sys.services WHERE name = N'syspolicy_event_listener')
    DROP SERVICE [syspolicy_event_listener]
GO
PRINT N'Dropping queue [syspolicy_event_queue]...'
GO
IF EXISTS (SELECT * FROM sys.service_queues WHERE name = N'syspolicy_event_queue')
    DROP QUEUE [syspolicy_event_queue]
GO
PRINT N'Creating queue [syspolicy_event_queue]...'
GO
CREATE QUEUE [syspolicy_event_queue]
GO

PRINT N'Creating service [syspolicy_event_listener]...'
GO
CREATE SERVICE [syspolicy_event_listener]
 ON QUEUE  [syspolicy_event_queue]
    ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);
GO

IF EXISTS (SELECT * FROM sys.procedures WHERE name = N'sp_syspolicy_events_reader')
    DROP PROCEDURE [sp_syspolicy_events_reader] 
GO
PRINT N'Creating procedure [sp_syspolicy_events_reader]...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_events_reader] 
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

	DECLARE @dh uniqueidentifier;
	DECLARE @mt sysname;
	DECLARE @body varbinary(max);
	DECLARE @msg nvarchar(max)

    BEGIN TRANSACTION;
    WAITFOR (RECEIVE TOP (1)
        @dh = conversation_handle,
        @mt = message_type_name,
        @body = message_body
        FROM [syspolicy_event_queue]), timeout 5000;
    WHILE (@dh is not null)
    BEGIN
        IF (@mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
        BEGIN
            -- @body contains the error
            DECLARE @bodyStr nvarchar(max)
            SET @bodyStr = convert(nvarchar(max), @body)
            RAISERROR (34001, 1,1, @bodyStr) with log;
            END CONVERSATION @dh;
        END
        IF (@mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
        BEGIN
            RAISERROR (34002, 1,1) with log;
            END CONVERSATION @dh;
        END
        IF (@mt = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification')
        BEGIN
            -- process the event
            BEGIN TRY
                EXEC [dbo].[sp_syspolicy_dispatch_event]  @event_data = @body, @synchronous = 0
            END TRY
            BEGIN CATCH
                -- report the error

                DECLARE @errorNumber int
                DECLARE @errorMessage nvarchar(max)
                SET @errorNumber = ERROR_NUMBER()
                SET @errorMessage = ERROR_MESSAGE()

                RAISERROR (34003, 1,1, @errorNumber, @errorMessage ) with log;
            END CATCH
        END
        -- every message is handled in its own transaction
        COMMIT TRANSACTION;
        SELECT @dh = null;
        BEGIN TRANSACTION;
        WAITFOR (RECEIVE TOP (1)
            @dh = conversation_handle,
            @mt = message_type_name,
            @body = message_body
            FROM [syspolicy_event_queue]), TIMEOUT 5000;
    END
    COMMIT;
END
GO

IF OBJECT_ID('[dbo].[syspolicy_configuration_internal]') IS NULL
BEGIN
    PRINT 'Creating table [dbo].[syspolicy_configuration_internal]...'
    CREATE TABLE [dbo].[syspolicy_configuration_internal] (
        name sysname PRIMARY KEY CLUSTERED NOT NULL,
        current_value sql_variant NOT NULL);
        
    INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
    VALUES (N'Enabled', 1);
    
    INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
    VALUES (N'HistoryRetentionInDays', 0);
    
    INSERT INTO [dbo].[syspolicy_configuration_internal] (name, current_value)
    VALUES (N'LogOnSuccess', 0);
END
GO


PRINT 'Creating view [dbo].[syspolicy_configuration] ...'
GO
CREATE VIEW [dbo].[syspolicy_configuration]
AS
    SELECT 
        name,
        CASE WHEN name = N'Enabled' and SERVERPROPERTY('EngineEdition') = 4 THEN 0 ELSE current_value END AS current_value
    FROM [dbo].[syspolicy_configuration_internal] 
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_set_config_history_retention] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_config_history_retention] 
	@value sql_variant
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
        SET current_value = @value
        WHERE name = N'HistoryRetentionInDays';
    
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_set_log_on_success] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_log_on_success] 
	@value sql_variant
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END

    UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
        SET current_value = @value
        WHERE name = N'LogOnSuccess';
    
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_set_config_enabled] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_set_config_enabled] 
	@value sql_variant
AS
BEGIN
	DECLARE @retval_check int;
	
	SET NOCOUNT ON
	
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check
	END
    
    DECLARE @val bit;
    SET @val = CONVERT(bit, @value);
    IF (@val = 1)
    BEGIN
	    DECLARE @engine_edition INT
		SELECT @engine_edition = CAST(SERVERPROPERTY('EngineEdition') AS INT)
		IF @engine_edition = 4 -- All SQL Express types + embedded
		BEGIN
			RAISERROR (34054, 16, 1)			
            RETURN 34054
		END
		
	    UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
	    SET current_value = @value
	    WHERE name = N'Enabled';
    
        -- enable policy automation
        ALTER QUEUE [syspolicy_event_queue] WITH ACTIVATION (STATUS = ON)

        EXEC sys.sp_syspolicy_update_ddl_trigger;
        EXEC sys.sp_syspolicy_update_event_notification;
    END
    ELSE
    BEGIN
	    UPDATE [msdb].[dbo].[syspolicy_configuration_internal]
	    SET current_value = @value
	    WHERE name = N'Enabled';

        -- disable policy automation
        ALTER QUEUE [syspolicy_event_queue] WITH ACTIVATION (STATUS = OFF)

        IF EXISTS (SELECT * FROM sys.server_event_notifications WHERE name = N'syspolicy_event_notification')
	        DROP EVENT NOTIFICATION [syspolicy_event_notification] ON SERVER 

        IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = N'syspolicy_server_trigger')
            DISABLE TRIGGER [syspolicy_server_trigger] ON ALL SERVER 
    END

END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_configure] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_configure]
    @name sysname,
    @value sql_variant
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole'
	IF (0 != @retval_check)
	BEGIN
		RETURN @retval_check
	END

    DECLARE @value_type sysname;
    
    IF (@name=N'Enabled')
    BEGIN
        SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
        IF (@value_type != 'int')
        BEGIN
            RAISERROR (34021, -1, -1, @name, @value_type);
            RETURN 34021;
        END
       
        EXEC msdb.[dbo].[sp_syspolicy_set_config_enabled] @value;
    END
    ELSE 
    IF (@name = N'HistoryRetentionInDays')
    BEGIN
        SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
        IF (@value_type != 'int')
        BEGIN
            RAISERROR (34021, -1, -1, @name, @value_type);
            RETURN 34021;
        END
        
        EXEC msdb.[dbo].[sp_syspolicy_set_config_history_retention] @value;
    END
    ELSE
    IF (@name=N'LogOnSuccess')
    BEGIN
        SET @value_type = CONVERT(sysname, SQL_VARIANT_PROPERTY(@value, 'BaseType'));
        IF (@value_type != 'int')
        BEGIN
            RAISERROR (34021, -1, -1, @name, @value_type);
            RETURN 34021;
        END
       
        EXEC msdb.[dbo].[sp_syspolicy_set_log_on_success] @value;
    END
    ELSE 
    BEGIN
        RAISERROR(34020, -1, -1, @name);
        RETURN 34020;
    END
    
    RETURN 0;
END
GO
PRINT 'Creating function [dbo].[fn_syspolicy_is_automation_enabled] ...'
GO
CREATE FUNCTION fn_syspolicy_is_automation_enabled()
RETURNS bit
AS
BEGIN
    DECLARE @ret bit;
    SELECT @ret = CONVERT(bit, current_value)
        FROM msdb.dbo.syspolicy_configuration 
        WHERE name = 'Enabled' 

    RETURN @ret;
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_repair_policy_automation] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_repair_policy_automation]
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check;
	END

    BEGIN TRANSACTION;

    BEGIN TRY
        SET NOCOUNT ON
        
        DECLARE @policies_copy TABLE (
                            policy_id int ,
                            name sysname NOT NULL,
                            condition_id int NOT NULL,
                            root_condition_id int NULL,
                            execution_mode int NOT NULL,
                            policy_category_id int NULL,
                            schedule_uid uniqueidentifier NULL,
                            description nvarchar(max) NOT NULL ,
                            help_text nvarchar(4000) NOT NULL ,
                            help_link nvarchar(2083) NOT NULL ,
                            object_set_id INT NULL,
                            is_enabled bit default 0 NOT NULL);

        INSERT INTO @policies_copy 
            SELECT          policy_id,
                            name, 
                            condition_id, 
                            root_condition_id, 
                            execution_mode, 
                            policy_category_id, 
                            schedule_uid, 
                            description,
                            help_text,
                            help_link,
                            object_set_id,
                            is_enabled
            FROM msdb.dbo.syspolicy_policies_internal;
        
        DELETE FROM syspolicy_policies_internal;
        
        SET IDENTITY_INSERT msdb.dbo.syspolicy_policies_internal ON
        INSERT INTO msdb.dbo.syspolicy_policies_internal (
                            policy_id,
                            name, 
                            condition_id, 
                            root_condition_id, 
                            execution_mode, 
                            policy_category_id, 
                            schedule_uid, 
                            description,
                            help_text,
                            help_link,
                            object_set_id,
                            is_enabled)
            SELECT 
                            policy_id,
                            name, 
                            condition_id, 
                            root_condition_id, 
                            execution_mode, 
                            policy_category_id, 
                            schedule_uid, 
                            description,
                            help_text,
                            help_link,
                            object_set_id,
                            is_enabled
            FROM @policies_copy;
            
        SET IDENTITY_INSERT msdb.dbo.syspolicy_policies_internal OFF;
        
        SET NOCOUNT OFF;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        RAISERROR (14351, -1, -1);
        RETURN 1;
    END CATCH

    -- commit the transaction we started
    COMMIT TRANSACTION;
    
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_purge_history] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_purge_history]
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check;
	END

    DECLARE @retention_interval_in_days_variant sql_variant
    SET @retention_interval_in_days_variant = (SELECT current_value 
                                        FROM msdb.dbo.syspolicy_configuration
                                        WHERE name = N'HistoryRetentionInDays');
                                        
    DECLARE @retention_interval_in_days int;
    SET @retention_interval_in_days = CONVERT(int, @retention_interval_in_days_variant);
    
    IF( @retention_interval_in_days <= 0)
        RETURN 0;
	
	DECLARE @cutoff_date datetime;
	SET @cutoff_date = DATEADD(day, -@retention_interval_in_days, GETDATE());

    -- delete old policy history records
    BEGIN TRANSACTION
    
    DELETE d 
    FROM msdb.dbo.syspolicy_policy_execution_history_details_internal d
    INNER JOIN msdb.dbo.syspolicy_policy_execution_history_internal h ON d.history_id = h.history_id
    WHERE h.end_date < @cutoff_date
    
    DELETE h
    FROM msdb.dbo.syspolicy_policy_execution_history_internal h
    WHERE h.end_date < @cutoff_date
    
    COMMIT TRANSACTION
    
    -- delete policy subscriptions that refer to the nonexistent databases
    DELETE s
    FROM msdb.dbo.syspolicy_policy_category_subscriptions_internal s
    LEFT OUTER JOIN master.sys.databases d ON s.target_object = d.name
    WHERE s.target_type = 'DATABASE' AND d.database_id IS NULL
    
    RETURN 0;
END
GO
PRINT 'Creating procedure [dbo].[sp_syspolicy_create_purge_job] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_create_purge_job]
AS
BEGIN
DECLARE @retval_check int;
EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
IF ( 0!= @retval_check)
BEGIN
	RETURN @retval_check;
END

-- create a policy history retention maintenance job
-- first check if this job already exists 
IF EXISTS (SELECT * 
            FROM msdb.dbo.syspolicy_configuration c
            WHERE c.name = 'PurgeHistoryJobGuid')
BEGIN
    RETURN;
END

BEGIN TRANSACTION;
DECLARE @ReturnCode INT;
SELECT @ReturnCode = 0;
DECLARE @job_name sysname;
-- create unique job name
SET @job_name = N'syspolicy_purge_history';
WHILE (EXISTS (SELECT * FROM msdb..sysjobs WHERE name = @job_name))
BEGIN
	SET @job_name = N'syspolicy_purge_history_' + RIGHT(STR(FLOOR(RAND() * 100000000)),8);
END

DECLARE @jobId BINARY(16);
EXEC @ReturnCode =  msdb.dbo.sp_add_job 
        @job_name=@job_name, 
		@enabled=1, 
		@notify_level_eventlog=0, 
		@notify_level_email=0, 
		@notify_level_netsend=0, 
		@notify_level_page=0, 
		@delete_level=0, 
		@owner_login_name=N'sa', 
		@job_id = @jobId OUTPUT;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

EXEC @ReturnCode = msdb.dbo.sp_add_jobstep 
        @job_id=@jobId, 
        @step_name=N'Verify that automation is enabled.', 
		@step_id=1, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=1, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, 
		@subsystem=N'TSQL', 
		@command=N'IF (msdb.dbo.fn_syspolicy_is_automation_enabled() != 1)
        BEGIN
            RAISERROR(34022, 16, 1)
        END', 
		@database_name=N'master', 
		@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

EXEC @ReturnCode = msdb.dbo.sp_add_jobstep 
        @job_id=@jobId, 
        @step_name=N'Purge history.', 
		@step_id=2, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, 
		@subsystem=N'TSQL', 
		@command=N'EXEC msdb.dbo.sp_syspolicy_purge_history', 
		@database_name=N'master', 
		@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

DECLARE @command nvarchar(1000);
DECLARE @serverName nvarchar(255)

set @serverName=Convert(nvarchar(255), SERVERPROPERTY(N'ServerName'))
IF ( (@serverName NOT LIKE '%\%') )
BEGIN
	-- Powershell requires that default instances are called DEFAULT
	SET @serverName = @serverName + '\DEFAULT'
END

SET @command = N'(Get-Item SQLSERVER:\SQLPolicy\' + @serverName + ').EraseSystemHealthPhantomRecords()';

EXEC @ReturnCode = msdb.dbo.sp_add_jobstep 
        @job_id=@jobId, 
        @step_name=N'Erase Phantom System Health Records.', 
		@step_id=3, 
		@cmdexec_success_code=0, 
		@on_success_action=1, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, 
		@subsystem=N'PowerShell', 
		@command=@command, 
		@database_name=N'master', 
		@flags=0;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = @@SERVERNAME;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

-- run this job every day at 2AM
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule 
        @job_id=@jobId, 
        @name=N'syspolicy_purge_history_schedule', 
		@enabled=1, 
		@freq_type=4, 
		@freq_interval=1, 
		@freq_subday_type=1, 
		@freq_subday_interval=0, 
		@freq_relative_interval=0, 
		@freq_recurrence_factor=0, 
		@active_start_date=20080101, 
		@active_end_date=99991231, 
		@active_start_time=20000, 
		@active_end_time=235959;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;

INSERT INTO [msdb].[dbo].[syspolicy_configuration_internal] (name, current_value)
VALUES (N'PurgeHistoryJobGuid', @jobId);

COMMIT TRANSACTION;
RETURN;

QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION;
END
GO

PRINT 'Creating procedure [dbo].[sp_syspolicy_purge_health_state] ...'
GO
CREATE PROCEDURE [dbo].[sp_syspolicy_purge_health_state]
    @target_tree_root_with_id nvarchar(400) = NULL
AS
BEGIN
	DECLARE @retval_check int;
	EXECUTE @retval_check = [dbo].[sp_syspolicy_check_membership] 'PolicyAdministratorRole';
	IF ( 0!= @retval_check)
	BEGIN
		RETURN @retval_check;
	END
	
	IF (@target_tree_root_with_id IS NULL)
	BEGIN
	    DELETE FROM msdb.dbo.syspolicy_system_health_state_internal;
	END
	ELSE
	BEGIN
	    DECLARE @target_mask nvarchar(801);
	    SET @target_mask = @target_tree_root_with_id;
	    -- we need to escape all the characters that can be part of the 
	    -- LIKE pattern
	    SET @target_mask = REPLACE(@target_mask, '[', '\[');
	    SET @target_mask = REPLACE(@target_mask, ']', '\]');
	    SET @target_mask = REPLACE(@target_mask, '_', '\_');
	    SET @target_mask = REPLACE(@target_mask, '%', '\%');
	    SET @target_mask = @target_mask + '%';
	    DELETE FROM msdb.dbo.syspolicy_system_health_state_internal
	        WHERE target_query_expression_with_id LIKE @target_mask ESCAPE '\';
	END
	
	RETURN 0;
END
GO

-----------------------------------------------------------
-- Security for policy objects
-----------------------------------------------------------
IF ( NOT EXISTS (SELECT * FROM sys.database_principals 
                    WHERE name = N'PolicyAdministratorRole' AND type = 'R'))
BEGIN
    CREATE ROLE [PolicyAdministratorRole]
END
ELSE -- if the role exists check to see if it has members
BEGIN
    IF NOT EXISTS (SELECT rm.member_principal_id
                FROM sys.database_principals dp 
                INNER JOIN sys.database_role_members rm ON rm.role_principal_id = dp.principal_id
                WHERE name = N'PolicyAdministratorRole' AND type = 'R')
    BEGIN
        -- if the role has no members drop and recreate it
        DROP ROLE [PolicyAdministratorRole]
        CREATE ROLE [PolicyAdministratorRole]
    END
END
GO
-- Policy administrator is also an agent operator
-- because we need to create jobs automatically
EXECUTE sp_addrolemember @rolename = 'SQLAgentOperatorRole' , 
                   @membername = 'PolicyAdministratorRole' 
GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals 
                    WHERE name = N'ServerGroupAdministratorRole' AND type = 'R'))
BEGIN
    CREATE ROLE [ServerGroupAdministratorRole]
END

GO
IF ( NOT EXISTS (SELECT * FROM sys.database_principals 
                    WHERE name = N'ServerGroupReaderRole' AND type = 'R'))
BEGIN
    CREATE ROLE [ServerGroupReaderRole]
END
GO
EXECUTE sp_addrolemember @rolename = 'ServerGroupReaderRole' , 
                   @membername = 'ServerGroupAdministratorRole' 

GO
CREATE PROCEDURE #provision_table @short_name sysname, @role_name sysname, @grant_public_select bit
AS
BEGIN
    DECLARE @stmt nvarchar(max)
    -- revoke table permissions
    SELECT @stmt = N'REVOKE DELETE, INSERT, REFERENCES, SELECT, UPDATE, ALTER, CONTROL, TAKE OWNERSHIP 
        ON [dbo].' + QUOTENAME(@short_name + N'_internal') + ' FROM [public] CASCADE'
    EXEC sp_executesql @stmt

    -- revoke view permissions
    SELECT @stmt = N'REVOKE ALTER, CONTROL, DELETE, INSERT, REFERENCES, SELECT, TAKE OWNERSHIP, UPDATE
        ON [dbo].' + QUOTENAME(@short_name ) + ' FROM [public] CASCADE'
    EXEC sp_executesql @stmt

    -- grant select on view 
    SELECT @stmt = N'GRANT SELECT ON [dbo].' + QUOTENAME(@short_name)+ ' TO ' + QUOTENAME(@role_name)
    EXEC sp_executesql @stmt

    if (@grant_public_select != 0)
    BEGIN
        SELECT @stmt = N'GRANT SELECT ON [dbo].' + QUOTENAME(@short_name)+ ' TO [public]'
        EXEC sp_executesql @stmt
    END
    
END
GO

-- public role can view all policy metadata
EXEC #provision_table N'syspolicy_conditions', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policies', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_categories', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_object_sets', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_target_sets', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_target_set_levels', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_category_subscriptions', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_system_health_state', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_execution_history', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_policy_execution_history_details', N'PolicyAdministratorRole', 1
EXEC #provision_table N'syspolicy_configuration', N'PolicyAdministratorRole', 1

-- Registered Server information is limited to the ServerGroupReaderRole, with no public access
EXEC #provision_table N'sysmanagement_shared_registered_servers', N'ServerGroupReaderRole', 0
EXEC #provision_table N'sysmanagement_shared_server_groups', N'ServerGroupReaderRole', 0
GO
DROP PROCEDURE #provision_table

GO
CREATE PROCEDURE #provision_sp @name sysname, @role_name sysname
AS
BEGIN
    DECLARE @stmt nvarchar(max)
    SELECT @stmt = N'REVOKE ALTER, CONTROL, EXECUTE, TAKE OWNERSHIP, VIEW DEFINITION
    ON [dbo].' + QUOTENAME(@name) + ' FROM [public] CASCADE'
    EXEC sp_executesql @stmt

    SELECT @stmt = N'GRANT EXECUTE ON [dbo].' + QUOTENAME(@name)+ ' TO ' + QUOTENAME(@role_name)
    EXEC sp_executesql @stmt
    
END
GO
EXEC #provision_sp N'sp_syspolicy_add_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_condition', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_condition', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_add_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_policy', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_add_target_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_target_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_add_target_set_level', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_target_set_level', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_add_policy_category_subscription', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy_category_subscription', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy_category_subscription', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_log_policy_execution_start', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_log_policy_execution_end', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_log_policy_execution_detail', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_add_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_rename_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_update_policy_category', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_policy_category', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_add_object_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_delete_object_set', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_verify_object_set_identifiers', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_dispatch_event', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_syspolicy_configure', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_purge_history', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_repair_policy_automation', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_purge_health_state', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_create_purge_job', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_log_on_success', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_config_enabled', N'PolicyAdministratorRole'
EXEC #provision_sp N'sp_syspolicy_set_config_history_retention', N'PolicyAdministratorRole'

EXEC #provision_sp N'sp_sysmanagement_update_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_rename_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_update_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_rename_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_move_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_delete_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_move_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_delete_shared_server_group', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_add_shared_registered_server', N'ServerGroupAdministratorRole'
EXEC #provision_sp N'sp_sysmanagement_add_shared_server_group', N'ServerGroupAdministratorRole'

GO
DROP PROCEDURE #provision_sp
GO
GRANT EXECUTE ON [dbo].[fn_syspolicy_is_automation_enabled] TO PUBLIC
GO 

IF EXISTS (SELECT * from sys.database_principals where name = N'##MS_PolicyEventProcessingLogin##')
    DROP USER [##MS_PolicyEventProcessingLogin##]
GO
use master
GO
IF EXISTS (SELECT * from sys.server_principals WHERE name = '##MS_PolicyEventProcessingLogin##')
BEGIN
    IF EXISTS (SELECT * from sys.server_triggers WHERE name = N'syspolicy_server_trigger')
        DROP TRIGGER [syspolicy_server_trigger] ON ALL SERVER
    DROP LOGIN [##MS_PolicyEventProcessingLogin##]
END
go
-- create event processing login with random password
DECLARE @newid uniqueidentifier
SET @newid = NEWID()
DECLARE @password varchar(255)
SELECT @password = QUOTENAME(CONVERT(varchar(255), @newid), '''')
DBCC TRACEON(4606,-1)
EXECUTE( N'CREATE LOGIN [##MS_PolicyEventProcessingLogin##] WITH PASSWORD=N' + @password + '')
DBCC TRACEOFF(4606,-1)
go
-- create t-sql execution login with random password
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = '##MS_PolicyTsqlExecutionLogin##')
BEGIN
    DECLARE @newid uniqueidentifier
    SET @newid = NEWID()
    DECLARE @password varchar(255)
    SELECT @password = QUOTENAME(CONVERT(varchar(255), @newid), '''')
    DBCC TRACEON(4606,-1)
    EXECUTE( N'CREATE LOGIN [##MS_PolicyTsqlExecutionLogin##] WITH PASSWORD=N' + @password + '')
    DBCC TRACEOFF(4606,-1)

    -- this login is used just for impersonation, no one should be able to connect
    ALTER LOGIN [##MS_PolicyTsqlExecutionLogin##] DISABLE

    GRANT VIEW ANY DEFINITION TO [##MS_PolicyTsqlExecutionLogin##]
    GRANT VIEW SERVER STATE TO [##MS_PolicyTsqlExecutionLogin##]
END
go

-- this login is used just for impersonation, no one should be able to connect
ALTER LOGIN [##MS_PolicyEventProcessingLogin##] DISABLE

go
USE [msdb]
go
CREATE USER [##MS_PolicyEventProcessingLogin##] FROM LOGIN [##MS_PolicyEventProcessingLogin##]
go
EXEC msdb.sys.sp_addrolemember @rolename = 'PolicyAdministratorRole', @membername = '##MS_PolicyEventProcessingLogin##'
go
GRANT EXECUTE ON [sp_syspolicy_events_reader] TO [##MS_PolicyEventProcessingLogin##]
go

IF NOT EXISTS ( SELECT * FROM sys.database_principals WHERE name = '##MS_PolicyTsqlExecutionLogin##')
BEGIN
    CREATE USER [##MS_PolicyTsqlExecutionLogin##] FROM LOGIN [##MS_PolicyTsqlExecutionLogin##]
    EXEC msdb.sys.sp_addrolemember @rolename = 'PolicyAdministratorRole', @membername = '##MS_PolicyTsqlExecutionLogin##'
END
GO

USE [master]
go
IF EXISTS (SELECT * from sys.database_principals where name = N'##MS_PolicyEventProcessingLogin##')
    DROP USER [##MS_PolicyEventProcessingLogin##]
go
CREATE USER [##MS_PolicyEventProcessingLogin##]
go
GRANT EXECUTE ON [sp_syspolicy_execute_policy] TO [##MS_PolicyEventProcessingLogin##]
go

USE [msdb]
go

PRINT N'Hook up the activation procedure to the queue...'
ALTER QUEUE [syspolicy_event_queue]
    WITH ACTIVATION (
        STATUS = ON,
        MAX_QUEUE_READERS = 1,
        PROCEDURE_NAME = [sp_syspolicy_events_reader],
        EXECUTE AS N'##MS_PolicyEventProcessingLogin##');
GO

-- if this script runs on an existing installation (e.g in an upgrade) we need to recreate 
-- the event notifications and the ddl triggers used for policy automation 
exec sys.sp_syspolicy_update_event_notification
exec sys.sp_syspolicy_update_ddl_trigger
GO


-------------------------------------------------------------------------------
-- End policy objects
-------------------------------------------------------------------------------


/**************************************************************/
/* Sign agent sps and add them to Off By Default component    */
/*                                                            */
/* Also sign SPs for other components located in MSDB         */
/**************************************************************/

-- List all of the stored procedures we need to sign with the Agent
-- signing certicate. Optionally if your SP belongs in the 'Agent XPs'
-- Off-by-default component, then specify 1 for the 'obdComponent'
-- column; If it belongs in 'DBMail XPs', specify 2.

create table #sp_table (name sysname, sign int, obdComponent int, bNewProc int)
go
insert into #sp_table values(N'sp_sqlagent_is_srvrolemember',               1, 0, 0)
insert into #sp_table values(N'sp_verify_category_identifiers',               1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy_identifiers',               1, 0, 0)
insert into #sp_table values(N'sp_verify_credential_identifiers',          1, 0, 0)
insert into #sp_table values(N'sp_verify_subsystem_identifiers',           1, 0, 0)
insert into #sp_table values(N'sp_verify_login_identifiers',               1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy',                  1, 0, 0)
insert into #sp_table values(N'sp_add_proxy',                     1, 0, 0)
insert into #sp_table values(N'sp_delete_proxy',                  1, 0, 0)
insert into #sp_table values(N'sp_update_proxy',                  1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_is_member',                  1, 0, 0)
insert into #sp_table values(N'sp_verify_proxy_permissions',               1, 0, 0)
insert into #sp_table values(N'sp_help_proxy',                    1, 0, 0)
insert into #sp_table values(N'sp_grant_proxy_to_subsystem',               1, 0, 0)
insert into #sp_table values(N'sp_grant_login_to_proxy',             1, 0, 0)
insert into #sp_table values(N'sp_revoke_login_from_proxy',             1, 0, 0)
insert into #sp_table values(N'sp_revoke_proxy_from_subsystem',               1, 0, 0)
insert into #sp_table values(N'sp_enum_proxy_for_subsystem',               1, 0, 0)
insert into #sp_table values(N'sp_enum_login_for_proxy',             1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_get_startup_info',              1, 1, 0)
insert into #sp_table values(N'sp_sqlagent_has_server_access',             1, 1, 0)
insert into #sp_table values(N'sp_sem_add_message',                  1, 0, 0)
insert into #sp_table values(N'sp_sem_drop_message',                 1, 0, 0)
insert into #sp_table values(N'sp_get_message_description',             1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_get_perf_counters',             1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_notify',                  1, 1, 0)
insert into #sp_table values(N'sp_is_sqlagent_starting',             1, 1, 0)
insert into #sp_table values(N'sp_verify_job_identifiers',              1, 0, 0)
insert into #sp_table values(N'sp_verify_schedule_identifiers',               1, 0, 0)
insert into #sp_table values(N'sp_verify_jobproc_caller',               1, 0, 0)
insert into #sp_table values(N'sp_downloaded_row_limiter',              1, 1, 0)
insert into #sp_table values(N'sp_post_msx_operation',                  1, 1, 0)
insert into #sp_table values(N'sp_verify_performance_condition',           1, 0, 0)
insert into #sp_table values(N'sp_verify_job_date',                  1, 0, 0)
insert into #sp_table values(N'sp_verify_job_time',                  1, 0, 0)
insert into #sp_table values(N'sp_verify_alert',                  1, 1, 0)
insert into #sp_table values(N'sp_update_alert',                  1, 0, 0)
insert into #sp_table values(N'sp_delete_job_references',               1, 0, 0)
insert into #sp_table values(N'sp_delete_all_msx_jobs',                 1, 0, 0)
insert into #sp_table values(N'sp_generate_target_server_job_assignment_sql',       1, 0, 0)
insert into #sp_table values(N'sp_generate_server_description',               1, 1, 0)
insert into #sp_table values(N'sp_msx_set_account',                  1, 1, 0)
insert into #sp_table values(N'sp_msx_get_account',                  1, 1, 0)
insert into #sp_table values(N'sp_delete_operator',                  1, 0, 0)
insert into #sp_table values(N'sp_msx_defect',                    1, 1, 0)
insert into #sp_table values(N'sp_msx_enlist',                    1, 1, 0)
insert into #sp_table values(N'sp_delete_targetserver',                 1, 0, 0)
insert into #sp_table values(N'sp_get_sqlagent_properties',             1, 1, 0)
insert into #sp_table values(N'sp_set_sqlagent_properties',             1, 1, 0)
insert into #sp_table values(N'sp_add_targetservergroup',               1, 0, 0)
insert into #sp_table values(N'sp_update_targetservergroup',               1, 0, 0)
insert into #sp_table values(N'sp_delete_targetservergroup',               1, 0, 0)
insert into #sp_table values(N'sp_help_targetservergroup',              1, 0, 0)
insert into #sp_table values(N'sp_add_targetsvrgrp_member',             1, 0, 0)
insert into #sp_table values(N'sp_delete_targetsvrgrp_member',             1, 0, 0)
insert into #sp_table values(N'sp_verify_category',                  1, 0, 0)
insert into #sp_table values(N'sp_add_category',                  1, 0, 0)
insert into #sp_table values(N'sp_update_category',                  1, 0, 0)
insert into #sp_table values(N'sp_delete_category',                  1, 0, 0)
insert into #sp_table values(N'sp_help_category',                 1, 0, 0)
insert into #sp_table values(N'sp_help_targetserver',                1, 0, 0)
insert into #sp_table values(N'sp_resync_targetserver',                 1, 0, 0)
insert into #sp_table values(N'sp_purge_jobhistory',                 1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory',                  1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_full',                  1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_summary',                  1, 0, 0)
insert into #sp_table values(N'sp_help_jobhistory_sem',                  1, 0, 0)
insert into #sp_table values(N'sp_add_jobserver',                 1, 0, 0)
insert into #sp_table values(N'sp_delete_jobserver',                 1, 0, 0)
insert into #sp_table values(N'sp_help_jobserver',                1, 0, 0)
insert into #sp_table values(N'sp_help_downloadlist',                1, 0, 0)
insert into #sp_table values(N'sp_enum_sqlagent_subsystems',               1, 0, 0)
insert into #sp_table values(N'sp_enum_sqlagent_subsystems_internal', 1, 0, 0)
insert into #sp_table values(N'sp_verify_subsystem',                 1, 1, 0)
insert into #sp_table values(N'sp_verify_subsystems',                 1, 0, 0)
insert into #sp_table values(N'sp_verify_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_add_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_attach_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_detach_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_update_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_delete_schedule',                  1, 0, 0)
insert into #sp_table values(N'sp_get_jobstep_db_username',             1, 0, 0)
insert into #sp_table values(N'sp_verify_jobstep',                1, 0, 0)
insert into #sp_table values(N'sp_add_jobstep_internal',             1, 0, 0)
insert into #sp_table values(N'sp_add_jobstep',                   1, 0, 0)
insert into #sp_table values(N'sp_update_jobstep',                1, 0, 0)
insert into #sp_table values(N'sp_delete_jobstep',                1, 0, 0)
insert into #sp_table values(N'sp_help_jobstep',                  1, 0, 0)
insert into #sp_table values(N'sp_write_sysjobstep_log',             1, 0, 0)
insert into #sp_table values(N'sp_help_jobsteplog',                  1, 0, 0)
insert into #sp_table values(N'sp_delete_jobsteplog',                1, 0, 0)
insert into #sp_table values(N'sp_get_schedule_description',               1, 1, 0)
insert into #sp_table values(N'sp_add_jobschedule',                  1, 0, 0)
insert into #sp_table values(N'sp_update_replication_job_parameter',          1, 0, 0)
insert into #sp_table values(N'sp_update_jobschedule',                  1, 0, 0)
insert into #sp_table values(N'sp_delete_jobschedule',                  1, 0, 0)
insert into #sp_table values(N'sp_help_schedule',                 1, 0, 0)
insert into #sp_table values(N'sp_help_jobschedule',                 1, 0, 0)
insert into #sp_table values(N'sp_verify_job',                    1, 1, 0)
insert into #sp_table values(N'sp_add_job',                    1, 0, 0)
insert into #sp_table values(N'sp_update_job',                    1, 0, 0)
insert into #sp_table values(N'sp_delete_job',                    1, 0, 0)
insert into #sp_table values(N'sp_get_composite_job_info',              1, 1, 0)
insert into #sp_table values(N'sp_help_job',                   1, 0, 0)
insert into #sp_table values(N'sp_help_jobcount ',                1, 0, 0)
insert into #sp_table values(N'sp_help_jobs_in_schedule',               1, 0, 0)
insert into #sp_table values(N'sp_manage_jobs_by_login',             1, 0, 0)
insert into #sp_table values(N'sp_apply_job_to_targets',             1, 0, 0)
insert into #sp_table values(N'sp_remove_job_from_targets',             1, 0, 0)
insert into #sp_table values(N'sp_get_job_alerts',                1, 0, 0)
insert into #sp_table values(N'sp_convert_jobid_to_char',               1, 0, 0)
insert into #sp_table values(N'sp_start_job',                     1, 0, 0)
insert into #sp_table values(N'sp_stop_job',                   1, 0, 0)
insert into #sp_table values(N'sp_cycle_agent_errorlog',             1, 0, 0)
insert into #sp_table values(N'sp_get_chunked_jobstep_params',             1, 0, 0)
insert into #sp_table values(N'sp_check_for_owned_jobs',             1, 0, 0)
insert into #sp_table values(N'sp_check_for_owned_jobsteps',               1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_refresh_job',             1, 0, 0)
insert into #sp_table values(N'sp_jobhistory_row_limiter',              1, 1, 0)
insert into #sp_table values(N'sp_sqlagent_log_jobhistory',             1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_check_msx_version',             1, 0, 0)
insert into #sp_table values(N'sp_sqlagent_probe_msx',                  1, 0, 0)
insert into #sp_table values(N'sp_set_local_time',                1, 1, 0)
insert into #sp_table values(N'sp_multi_server_job_summary',               1, 0, 0)
insert into #sp_table values(N'sp_target_server_summary',               1, 0, 0)
insert into #sp_table values(N'sp_uniquetaskname',                1, 0, 0)
insert into #sp_table values(N'sp_addtask',                    1, 0, 0)
insert into #sp_table values(N'sp_droptask',                   1, 0, 0)
insert into #sp_table values(N'sp_add_alert_internal',                  1, 0, 0)
insert into #sp_table values(N'sp_add_alert',                     1, 0, 0)
insert into #sp_table values(N'sp_delete_alert',                  1, 0, 0)
insert into #sp_table values(N'sp_help_alert',                    1, 0, 0)
insert into #sp_table values(N'sp_verify_operator',                  1, 0, 0)
insert into #sp_table values(N'sp_add_operator',                  1, 0, 0)
insert into #sp_table values(N'sp_update_operator',                  1, 1, 0)
insert into #sp_table values(N'sp_help_operator',                 1, 0, 0)
insert into #sp_table values(N'sp_help_operator_jobs',                  1, 0, 0)
insert into #sp_table values(N'sp_verify_operator_identifiers',               1, 0, 0)
insert into #sp_table values(N'sp_notify_operator',                  1, 0, 0)
insert into #sp_table values(N'sp_verify_notification',                 1, 0, 0)
insert into #sp_table values(N'sp_add_notification',                 1, 0, 0)
insert into #sp_table values(N'sp_update_notification',                 1, 0, 0)
insert into #sp_table values(N'sp_delete_notification',                 1, 0, 0)
insert into #sp_table values(N'sp_help_notification',                1, 0, 0)
insert into #sp_table values(N'sp_help_jobactivity',                 1, 0, 0)
insert into #sp_table values(N'sp_enlist_tsx',                    1, 1, 0)
insert into #sp_table values(N'trig_targetserver_insert',               1, 0, 0)

-- Database Mail configuration procs
insert into #sp_table values(N'sysmail_verify_accountparams_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_verify_principal_sp',               1, 0, 0)
insert into #sp_table values(N'sysmail_verify_profile_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_verify_account_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_add_profile_sp',                 1, 0, 0)
insert into #sp_table values(N'sysmail_update_profile_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_delete_profile_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_help_profile_sp',             1, 0, 0)
insert into #sp_table values(N'sysmail_create_user_credential_sp',            1, 0, 0)
insert into #sp_table values(N'sysmail_alter_user_credential_sp',          1, 0, 0)
insert into #sp_table values(N'sysmail_drop_user_credential_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_add_account_sp',                 1, 0, 0)
insert into #sp_table values(N'sysmail_update_account_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_delete_account_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_help_account_sp',             1, 0, 0)
insert into #sp_table values(N'sysmail_help_admin_account_sp',             1, 0, 0)
insert into #sp_table values(N'sysmail_add_profileaccount_sp',             1, 0, 0)
insert into #sp_table values(N'sysmail_update_profileaccount_sp',          1, 0, 0)
insert into #sp_table values(N'sysmail_delete_profileaccount_sp',          1, 0, 0)
insert into #sp_table values(N'sysmail_help_profileaccount_sp',               1, 0, 0)
insert into #sp_table values(N'sysmail_configure_sp',                1, 0, 0)
insert into #sp_table values(N'sysmail_help_configure_sp',              1, 0, 0)
insert into #sp_table values(N'sysmail_help_configure_value_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_add_principalprofile_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_update_principalprofile_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_delete_principalprofile_sp',           1, 0, 0)
insert into #sp_table values(N'sysmail_help_principalprofile_sp',          1, 0, 0)

-- Database Mail: mail host database specific procs
insert into #sp_table values(N'sysmail_start_sp',             1, 2, 0)
insert into #sp_table values(N'sysmail_stop_sp',              1, 2, 0)
insert into #sp_table values(N'sysmail_logmailevent_sp',      1, 0, 0)
insert into #sp_table values(N'sp_SendMailMessage',           1, 0, 0)
insert into #sp_table values(N'sp_isprohibited',              1, 0, 0)
insert into #sp_table values(N'sp_SendMailQueues',            1, 0, 0)
insert into #sp_table values(N'sp_ProcessResponse',           1, 0, 0)
insert into #sp_table values(N'sp_MailItemResultSets',        1, 0, 0)
insert into #sp_table values(N'sp_process_DialogTimer',       1, 0, 0)
insert into #sp_table values(N'sp_readrequest',               1, 0, 0)
insert into #sp_table values(N'sp_GetAttachmentData',         1, 0, 0)
insert into #sp_table values(N'sp_RunMailQuery',              1, 0, 0)
insert into #sp_table values(N'sysmail_help_queue_sp',        1, 0, 0)
insert into #sp_table values(N'sysmail_help_status_sp',       1, 2, 0)
insert into #sp_table values(N'sysmail_delete_mailitems_sp',  1, 0, 0)
insert into #sp_table values(N'sysmail_delete_log_sp',        1, 0, 0)
insert into #sp_table values(N'sp_validate_user',             1, 2, 0)
insert into #sp_table values(N'sp_send_dbmail',               1, 2, 0)
insert into #sp_table values(N'sp_ExternalMailQueueListener', 1, 0, 0)
insert into #sp_table values(N'sp_sysmail_activate',          1, 0, 0)
insert into #sp_table values(N'sp_get_script',                1, 0, 0)

-- Maintenance Plans
insert into #sp_table values(N'sp_maintplan_delete_log',             1, 0, 0)
insert into #sp_table values(N'sp_maintplan_delete_subplan',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_open_logentry',             1, 0, 0)
insert into #sp_table values(N'sp_maintplan_close_logentry',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_log',             1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_subplan',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_delete_plan',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_start',                  1, 0, 0)
insert into #sp_table values(N'sp_clear_dbmaintplan_by_db',             1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan',             1, 0, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan',             1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan_db',             1, 0, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan_db',             1, 0, 0)
insert into #sp_table values(N'sp_add_maintenance_plan_job',               1, 1, 0)
insert into #sp_table values(N'sp_delete_maintenance_plan_job',               1, 0, 0)
insert into #sp_table values(N'sp_help_maintenance_plan',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_update_subplan_tsx',               1, 0, 0)
insert into #sp_table values(N'sp_maintplan_subplans_by_job',               1, 0, 0)

-- Log Shipping
insert into #sp_table values(N'sp_add_log_shipping_monitor_jobs',          1, 0, 0)
insert into #sp_table values(N'sp_add_log_shipping_primary',               1, 0, 0)
insert into #sp_table values(N'sp_add_log_shipping_secondary',             1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_monitor_jobs',          1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_primary',               1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_secondary ',            1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_in_sync',             1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_get_date_from_file ',          1, 0, 0)
insert into #sp_table values(N'sp_get_log_shipping_monitor_info',          1, 0, 0)
insert into #sp_table values(N'sp_update_log_shipping_monitor_info',          1, 0, 0)
insert into #sp_table values(N'sp_delete_log_shipping_monitor_info',          1, 0, 0)
insert into #sp_table values(N'sp_remove_log_shipping_monitor_account',          1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_monitor_backup',               1, 0, 0)
insert into #sp_table values(N'sp_log_shipping_monitor_restore',           1, 0, 0)
insert into #sp_table values(N'sp_change_monitor_role',                 1, 0, 0)
insert into #sp_table values(N'sp_create_log_shipping_monitor_account',          1, 0, 0)

-- DTS
insert into #sp_table values(N'sp_get_dtsversion',                1, 0, 0)
insert into #sp_table values(N'sp_make_dtspackagename',                 1, 0, 0)
insert into #sp_table values(N'sp_add_dtspackage',                1, 0, 0)
insert into #sp_table values(N'sp_drop_dtspackage',                  1, 0, 0)
insert into #sp_table values(N'sp_reassign_dtspackageowner',               1, 0, 0)
insert into #sp_table values(N'sp_get_dtspackage',                1, 0, 0)
insert into #sp_table values(N'sp_reassign_dtspackagecategory',               1, 0, 0)
insert into #sp_table values(N'sp_enum_dtspackages',                 1, 0, 0)
insert into #sp_table values(N'sp_add_dtscategory',                  1, 0, 0)
insert into #sp_table values(N'sp_drop_dtscategory',                 1, 0, 0)
insert into #sp_table values(N'sp_modify_dtscategory',                  1, 0, 0)
insert into #sp_table values(N'sp_enum_dtscategories',                  1, 0, 0)
insert into #sp_table values(N'sp_log_dtspackage_begin',             1, 0, 0)
insert into #sp_table values(N'sp_log_dtspackage_end',                  1, 0, 0)
insert into #sp_table values(N'sp_log_dtsstep_begin',                1, 0, 0)
insert into #sp_table values(N'sp_log_dtsstep_end',                  1, 0, 0)
insert into #sp_table values(N'sp_log_dtstask',                   1, 0, 0)
insert into #sp_table values(N'sp_enum_dtspackagelog',                  1, 0, 0)
insert into #sp_table values(N'sp_enum_dtssteplog',                  1, 0, 0)
insert into #sp_table values(N'sp_enum_dtstasklog',                  1, 0, 0)
insert into #sp_table values(N'sp_dump_dtslog_all',                  1, 0, 0)
insert into #sp_table values(N'sp_dump_dtspackagelog',                  1, 0, 0)
insert into #sp_table values(N'sp_dump_dtssteplog',                  1, 0, 0)
insert into #sp_table values(N'sp_dump_dtstasklog',                  1, 0, 0)
insert into #sp_table values(N'sp_dts_secure',						1, 0, 0)
insert into #sp_table values(N'sp_ssis_addlogentry',                  1, 0, 0)
insert into #sp_table values(N'sp_ssis_listpackages',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_listfolders',                  1, 0, 0)
insert into #sp_table values(N'sp_ssis_deletepackage',                1, 0, 0)
insert into #sp_table values(N'sp_ssis_deletefolder',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_getpackage',                1, 0, 0)
insert into #sp_table values(N'sp_ssis_getfolder',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_putpackage',                1, 0, 0)
insert into #sp_table values(N'sp_ssis_addfolder',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_renamefolder',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_setpackageroles',                 1, 0, 0)
insert into #sp_table values(N'sp_ssis_getpackageroles',                 1, 0, 0)
go

/**************************************************************/
/* Mark system objects                                        */
/**************************************************************/
declare  @start datetime
      ,@name  sysname
select @start = start from #InstMsdb
-- As a temporary solution, exclude the syscollector_collection_sets table from being a system table
declare newsysobjs cursor for select name from sys.objects where schema_id = 1 and create_date >= @start
open newsysobjs
fetch next from newsysobjs into @name
while @@fetch_status = 0
begin
   Exec sp_MS_marksystemobject @name
   update #sp_table set bNewProc = 1 where name = @name
   fetch next from newsysobjs into @name
end
deallocate newsysobjs
drop table #InstMsdb
go

PRINT 'Signing sps ...'
-- Create certificate to sign Agent sps
--
declare @certError int

if exists (select * from sys.certificates where name = '##MS_AgentSigningCertificate##')
begin
   PRINT 'Dropping existing Agent certificate ...'
   drop certificate [##MS_AgentSigningCertificate##]
   select @certError = @@error
   IF (@certError <> 0)
   BEGIN
       select 'Cannot drop existing certificate. Objects still signed by ##MS_AgentSigningCertificate##' = object_name(crypts.major_id) 
       from sys.crypt_properties crypts, sys.certificates certs
       where crypts.thumbprint = certs.thumbprint
       and crypts.class = 1
       and certs.name = '##MS_AgentSigningCertificate##'
   
       RAISERROR('Cannot drop existing ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
   END
end

-- If the temp table #SqlAgentSignatures exists, then this script is running as part
-- of an upgrade from a previous build of sql server. In this case we want to sign
-- the Agent procedures using the same signatures that exist in a clean install
-- of this same build. Those signatures are in #SqlAgentSignatures. To do this
-- we create the certificate from the .cer file.
--
-- In the non-upgrade case, meaning that this script is being run during the build
-- of the SQL Server product itself, we simply create the certificate from scratch.

CREATE TABLE #InstmsdbAgentCertPath (AgentCert NVARCHAR(1100))
DECLARE @certificate_name NVARCHAR(1100) -- space for path + MS_AgentSigningCertificate.cer
IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN

    -- We need agent XP's to be on in order to lookup the path to our instance install folder.
    DECLARE @advopt_old_value int
    DECLARE @comp_old_value int
    EXEC #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out

    DECLARE @InstallRootPath nvarchar(1024)

    -- Note: This is an _instance_ registry lookup, so it will
    -- automatically insert the right instance name after the "Microsoft
    -- SQL Server" part of the path, thus looking in a path like
    -- 'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.INST1\Setup'
    EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SOFTWARE\Microsoft\Microsoft SQL Server\Setup', N'SQLPath', @InstallRootPath OUTPUT

    -- Restore Agent XPs to previous state
    EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value

    IF @InstallRootPath IS NULL
    BEGIN
       RAISERROR('Cannot find instance-specific registry path for SOFTWARE\Microsoft\Microsoft SQL Server\Setup\SqlPath. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
    END

    -- Now find our certificate in the Install folder, placed there by setup.
    SELECT @InstallRootPath = @InstallRootPath + N'\Install'

    select @certificate_name = @InstallRootPath + N'\MS_AgentSigningCertificate.cer'

    -- Remember this file path so we can import it into master later
    insert #InstmsdbAgentCertPath(AgentCert) VALUES (@certificate_name)
    PRINT 'Updated #InstmsdbAgentCertPath with value ' + @certificate_name

    -- Handle single quotes in the directory name since this string is going to be passed to EXECUTE
    DECLARE @certificate_nameQuoted NVARCHAR(2200)
    SELECT  @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''

    PRINT 'Creating ##MS_AgentSigningCertificate## from ' + @certificate_name
    EXECUTE(N'create certificate [##MS_AgentSigningCertificate##] from file = ' + @certificate_nameQuoted)
    select @certError = @@error

    IF (@certError <> 0)
    BEGIN
       RAISERROR('Cannot create ##MS_AgentSigningCertificate## from file. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
    END
END
ELSE
BEGIN
   dbcc traceon(4606,-1) -- Ignore domain policy about weak password
   create certificate [##MS_AgentSigningCertificate##] 
      encryption by password = 'Yukon90_'
      with subject = 'MS_AgentSigningCertificate'
   select @certError = @@error
   dbcc traceoff(4606,-1)

   IF (@certError <> 0)
   BEGIN
      RAISERROR('Cannot create ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
   END

   --create a temporary database in order to get the path to the 'Data' folder
   IF (EXISTS (SELECT name
                   FROM master.dbo.sysdatabases
                   WHERE (name = N'temp_MS_AgentSigningCertificate_database')))
   BEGIN
     DROP DATABASE temp_MS_AgentSigningCertificate_database
   END

   CREATE DATABASE temp_MS_AgentSigningCertificate_database
   
   -- Note: master.dbo.sysaltfiles's filename column is 260 nvarchars
   DECLARE @dataDirName NVARCHAR(520)
   SELECT @dataDirName = SUBSTRING(filename, 1, CHARINDEX(N'temp_MS_AgentSigningCertificate_database.mdf', filename) - 1)
     FROM master.dbo.sysaltfiles
     WHERE (name = N'temp_MS_AgentSigningCertificate_database')
   
   if (@dataDirName is null)
      RAISERROR('Cannot deduce path for temporary certificate ##MS_AgentSigningCertificate##. Was temp_MS_AgentSigningCertificate_database not created? INSTMSDB.SQL terminating.', 20, 127) WITH LOG
   
   SELECT @certificate_name = @dataDirName + 'MS_AgentSigningCertificate.cer'

   -- Remember this file path so we can import it into master later
   insert #InstmsdbAgentCertPath(AgentCert) VALUES (@certificate_name)
   PRINT 'Created #InstmsdbAgentCertPath'
   
   -- drop temporary database
   IF (EXISTS (SELECT name
                   FROM master.dbo.sysdatabases
                   WHERE (name = N'temp_MS_AgentSigningCertificate_database')))
   BEGIN
     DROP DATABASE temp_MS_AgentSigningCertificate_database
   END
END

go


BEGIN TRANSACTION
declare @sp sysname
declare @exec_str nvarchar(1024)
declare @sign int
declare @obdComponent int
declare @bNewProc int

declare @bUseExistingSignature int
set @bUseExistingSignature = 0
IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
    set @bUseExistingSignature = 1
END

declare @err_str nvarchar(1024)
declare ms_crs_sps cursor global for select name, sign, obdComponent, bNewProc from #sp_table 
open ms_crs_sps
fetch next from ms_crs_sps into @sp, @sign, @obdComponent, @bNewProc
while @@fetch_status = 0
begin
   if exists(select * from sys.objects where name = @sp)
   begin
      print 'processing sp: ' + @sp
      if (@sign = 1)
      begin
         if (@bUseExistingSignature = 1)
         begin
            declare @signature varbinary(max)
            select @signature = signature
               from #SqlAgentSignatures
               where object_name = @sp

            if (@signature is null)
            begin
               set @err_str = 'Cannot find existing signature for stored procedure ' + @sp + '. Terminating.'
               RAISERROR(@err_str, 20, 127) WITH LOG
               ROLLBACK TRANSACTION
               return
            end

            set @exec_str = N'add signature to ' + @sp + N' by certificate [##MS_AgentSigningCertificate##] with signature = ' + CONVERT(nvarchar(max), @signature, 1)
         end
         else
         begin
            set @exec_str = N'add signature to ' + @sp + N' by certificate [##MS_AgentSigningCertificate##] with password = ''Yukon90_'''
         end
         Execute(@exec_str)
         if (@@error <> 0)
         begin
            set @err_str = 'Cannot sign stored procedure ' + @sp + '. Terminating.'
            RAISERROR(@err_str, 20, 127) WITH LOG
            ROLLBACK TRANSACTION
            return
         end
      end

      -- If there is a new procedure that goes in a component, put it there
      if (@obdComponent > 0 and @bNewProc > 0)
      begin
         if (@obdComponent = 1) -- SQLAgent
             set @exec_str = N'exec sp_AddFunctionalUnitToComponent N''Agent XPs'', N''' + @sp + N''''

         else if (@obdComponent = 2) -- DbMail
             set @exec_str = N'exec sp_AddFunctionalUnitToComponent N''Database Mail XPs'', N''' + @sp + N''''
 
         Execute(@exec_str)
         if (@@error <> 0)
         begin
            RAISERROR('Cannot add stored procedure to component. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
            ROLLBACK TRANSACTION
            return
         end
      end

   end
   fetch next from ms_crs_sps into @sp, @sign, @obdComponent, @bNewProc
end
close ms_crs_sps
deallocate ms_crs_sps
COMMIT TRANSACTION
go
drop table #sp_table
go

PRINT 'Succesfully signed sps'

DECLARE @certificate_name NVARCHAR(1100)
select @certificate_name = AgentCert
   from #InstmsdbAgentCertPath

-- Handle single quotes in the directory name since this string is going to be passed to EXECUTE
-- in both BACKUP CERT and CREATE CERT below.
DECLARE @certificate_nameQuoted NVARCHAR(2200)
SELECT  @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''

-- If this is not an upgrade, then we made our certificate from scratch.
-- Export it to a new file so that it can be imported into the master database.
IF (OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
   -- Drop certificate private key. When we export to a file just below,
   -- the file will not include the private key.
   alter certificate [##MS_AgentSigningCertificate##] remove private key

   IF (@@error <> 0)
      RAISERROR('Cannot alter ##MS_AgentSigningCertificate## in msdb. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

   -- Now we export the certificate to a file so that it can be imported into the master database.
   -- Use the data directory to persist the file.
   --
   if (@certificate_name is null)
      RAISERROR('Cannot deduce path for temporary certificate ##MS_AgentSigningCertificate##.', 20, 127) WITH LOG

   declare @certError int

   PRINT 'Exporting ##MS_AgentSigningCertificate## to ' + @certificate_name
   BEGIN TRY
      EXECUTE(N'backup certificate [##MS_AgentSigningCertificate##] to file = ' + @certificate_nameQuoted)
      select @certError = @@error
   END TRY
   BEGIN CATCH
      -- Error 15240 happens when instmsdb.sql is run repeatedly and directly on a sql server, so the
      -- certificate already exists on disk and so the file cannot be written.
      -- It should not happen during the mkmastr build stage since the .cer file was already deleted.
      if (ERROR_NUMBER() != 15240)
      BEGIN
         select @certError = ERROR_NUMBER()
         PRINT 'Error ' + @certError + ' backing up certificate.'
      END
      ELSE
      BEGIN
         PRINT 'Could not export certificate, trying again with random name. If this is a mkmastr build then this is an error.'
         SELECT @certificate_name = SUBSTRING(@certificate_name, 1, CHARINDEX(N'.cer', @certificate_name) - 1) + 
                                    CONVERT(NVARCHAR(520), NEWID()) + N'.cer' 
         SELECT @certificate_nameQuoted = '''' + REPLACE(@certificate_name, '''', '''''') + ''''

         update #InstmsdbAgentCertPath set AgentCert = @certificate_name

         PRINT 'Exporting ##MS_AgentSigningCertificate## to ' + @certificate_name 
         EXECUTE(N'backup certificate [##MS_AgentSigningCertificate##] to file = ' + @certificate_nameQuoted)
         select @certError = @@error
      END
   END CATCH
   
   IF (@certError <> 0)
      RAISERROR('Cannot backup ##MS_AgentSigningCertificate##. INSTMSDB.SQL terminating.', 20, 127) WITH LOG
END

drop table #InstmsdbAgentCertPath

-- Now we want to grant the signed stored procedures access to the
-- master database. To allow the cross-database call from msdb, we
-- will recreate the Agent certificate in the master database and
-- grant execute permission to it.

-- Switch to master so the certificate is recreated there
use master

if exists (select * from sys.database_principals where name = '##MS_AgentSigningCertificate##')
   drop user [##MS_AgentSigningCertificate##]

if exists (select * from sys.server_principals where name = '##MS_AgentSigningCertificate##')
   drop login [##MS_AgentSigningCertificate##]

if exists (select * from sys.certificates where name = '##MS_AgentSigningCertificate##')
   drop certificate [##MS_AgentSigningCertificate##]

-- Recreate the certificate (minus the private key, which we dropped earlier) from the file
-- into the master database.
PRINT 'Creating ##MS_AgentSigningCertificate## in master from ' + @certificate_name
execute(N'create certificate [##MS_AgentSigningCertificate##] from file = ' + @certificate_nameQuoted)
IF (@@error <> 0)
   RAISERROR('Cannot create ##MS_AgentSigningCertificate## certificate in master. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

-- create a login in the master database based on this certicate.
--
create login [##MS_AgentSigningCertificate##] from certificate [##MS_AgentSigningCertificate##]
IF (@@error <> 0)
   RAISERROR('Cannot create ##MS_AgentSigningCertificate## login. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

-- create certificate-based user for execution granting
--
create user [##MS_AgentSigningCertificate##] for certificate [##MS_AgentSigningCertificate##]
IF (@@error <> 0)
   RAISERROR('Cannot create ##MS_AgentSigningCertificate## user. INSTMSDB.SQL terminating.', 20, 127) WITH LOG

-- enable certificate for OBD
--
exec sys.sp_SetOBDCertificate N'##MS_AgentSigningCertificate##',N'ON'

grant execute to [##MS_AgentSigningCertificate##]
PRINT 'Successfully granted execute permission in master to ##MS_AgentSigningCertificate##.'

use msdb
go

--
-- End of signing sps
go

if not exists (select * from [dbo].[sysssispackagefolders] where [folderid] = '00000000-0000-0000-0000-000000000000')
BEGIN
-- Insert our root folder
DECLARE  @advopt_old_value    INT 
DECLARE  @comp_old_value   INT
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out
EXEC sp_ssis_addfolder NULL, '', '00000000-0000-0000-0000-000000000000'
-- Insert the 'Maintenance Plans' node at the root.
-- Note this GUID must never change - 08aa12d5-8f98-4dab-a4fc-980b150a5dc8
EXEC sp_ssis_addfolder '00000000-0000-0000-0000-000000000000', 'Maintenance Plans', '08aa12d5-8f98-4dab-a4fc-980b150a5dc8'
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value
END
GO

/**************************************************************/
/* Enable Logshipping (Yukon)                                 */
/**************************************************************/
declare @retcode int
exec @retcode = sys.sp_logshippinginstallmetadata
if (@retcode = 0)
begin
raiserror('Logshipping enabled successfully', 10, 1)
end
else
begin
raiserror('Logshipping not enabled for this edition', 10, 1)
end
go

/**************************************************************/
/* Drop auxilary procedure to enable OBD component          */
/**************************************************************/
DROP PROCEDURE #sp_enable_component 
go
DROP PROCEDURE #sp_restore_component_state 
go

-- enable policy checking 
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = N'syspolicy_server_trigger')
    ENABLE TRIGGER [syspolicy_server_trigger] ON ALL SERVER 

-- Restore old state of 'allow updates'
EXECUTE master.dbo.sp_configure N'allow updates', 0
go
RECONFIGURE WITH OVERRIDE
go

PRINT ''
PRINT '----------------------------------'
PRINT 'Execution of INSTMSDB.SQL complete'
PRINT '----------------------------------'
go

CHECKPOINT
go
use msdb
go

DECLARE @CMDExec        sysname

EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',
                                        N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems',
                                        N'CmdExec',
                                        @CMDExec OUTPUT,
                                        N'no_output'
IF @CMDExec IS NOT NULL                                        
BEGIN                                        
  PRINT ''
  PRINT 'Remove subsystem definition from registry...'
  --remove subsystem definition from registry and populate subsystem table
  DECLARE @ret INT
  EXEC @ret = master..xp_instance_regdeletekey N'HKEY_LOCAL_MACHINE',
                          N'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent\SubSystems'
  IF @ret <> 0
    RAISERROR('Failed to remove subsystems definition from registry', 10, 127) 
END

PRINT ''
PRINT 'Populate syssubsystem table...'

EXEC @ret = sp_enum_sqlagent_subsystems
IF @ret <> 0
  RAISERROR('Failed to add subsystems definition to syssubsystem table. Upgrade script terminating', 20, 127) WITH LOG
go
--restore Shiloh object permission
DECLARE @state_desc			  nvarchar(60)
DECLARE @permission_name	sysname
DECLARE @object_name		  sysname
DECLARE @grantee_name		  sysname 

DECLARE perms_set_cursor CURSOR LOCAL FOR 
	SELECT state_desc, permission_name, object_name, grantee_name from msdb.dbo.upgrade_perms

OPEN perms_set_cursor
   FETCH NEXT FROM perms_set_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
   WHILE (@@fetch_status = 0)
   BEGIN
      --PRINT @state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name
      BEGIN TRY
        EXEC (@state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name)
      END TRY
      BEGIN CATCH
      END CATCH
      FETCH NEXT FROM perms_set_cursor INTO @state_desc, @permission_name, @object_name, @grantee_name
   END
DEALLOCATE perms_set_cursor
--remove public from SQLAgent Shiloh procedures
PRINT ''
PRINT 'Revoke any permission to public role...'
BEGIN TRY
REVOKE ALL ON sp_add_alert																	FROM PUBLIC
REVOKE ALL ON sp_add_category																FROM PUBLIC
REVOKE ALL ON sp_add_job																		FROM PUBLIC
REVOKE ALL ON sp_add_jobschedule														FROM PUBLIC
REVOKE ALL ON sp_add_jobserver															FROM PUBLIC
REVOKE ALL ON sp_add_jobstep																FROM PUBLIC
REVOKE ALL ON sp_add_notification														FROM PUBLIC
REVOKE ALL ON sp_add_operator																FROM PUBLIC
REVOKE ALL ON sp_add_targetservergroup											FROM PUBLIC
REVOKE ALL ON sp_add_targetsvrgrp_member										FROM PUBLIC
REVOKE ALL ON sp_apply_job_to_targets												FROM PUBLIC
REVOKE ALL ON sp_convert_jobid_to_char											FROM PUBLIC
REVOKE ALL ON sp_delete_alert																FROM PUBLIC
REVOKE ALL ON sp_delete_all_msx_jobs												FROM PUBLIC
REVOKE ALL ON sp_delete_category														FROM PUBLIC
REVOKE ALL ON sp_delete_job																	FROM PUBLIC
REVOKE ALL ON sp_delete_job_references											FROM PUBLIC
REVOKE ALL ON sp_delete_jobschedule													FROM PUBLIC
REVOKE ALL ON sp_delete_jobserver														FROM PUBLIC
REVOKE ALL ON sp_delete_jobstep															FROM PUBLIC
REVOKE ALL ON sp_delete_notification												FROM PUBLIC
REVOKE ALL ON sp_delete_operator														FROM PUBLIC
REVOKE ALL ON sp_delete_targetserver												FROM PUBLIC
REVOKE ALL ON sp_delete_targetservergroup										FROM PUBLIC
REVOKE ALL ON sp_delete_targetsvrgrp_member									FROM PUBLIC
REVOKE ALL ON sp_downloaded_row_limiter											FROM PUBLIC
REVOKE ALL ON sp_generate_server_description								FROM PUBLIC
REVOKE ALL ON sp_generate_target_server_job_assignment_sql	FROM PUBLIC
REVOKE ALL ON sp_get_chunked_jobstep_params									FROM PUBLIC
REVOKE ALL ON sp_get_composite_job_info											FROM PUBLIC
REVOKE ALL ON sp_get_job_alerts															FROM PUBLIC
REVOKE ALL ON sp_get_jobstep_db_username										FROM PUBLIC
REVOKE ALL ON sp_get_message_description										FROM PUBLIC
REVOKE ALL ON sp_get_schedule_description										FROM PUBLIC
REVOKE ALL ON sp_get_sqlagent_properties										FROM PUBLIC
REVOKE ALL ON sp_help_alert																	FROM PUBLIC
REVOKE ALL ON sp_help_category															FROM PUBLIC
REVOKE ALL ON sp_help_downloadlist													FROM PUBLIC
REVOKE ALL ON sp_help_job																		FROM PUBLIC
REVOKE ALL ON sp_help_jobhistory														FROM PUBLIC
REVOKE ALL ON sp_help_jobschedule														FROM PUBLIC
REVOKE ALL ON sp_help_jobserver															FROM PUBLIC
REVOKE ALL ON sp_help_jobstep																FROM PUBLIC
REVOKE ALL ON sp_help_notification													FROM PUBLIC
REVOKE ALL ON sp_help_operator															FROM PUBLIC
REVOKE ALL ON sp_help_operator_jobs													FROM PUBLIC
REVOKE ALL ON sp_help_targetserver													FROM PUBLIC
REVOKE ALL ON sp_help_targetservergroup											FROM PUBLIC
REVOKE ALL ON sp_is_sqlagent_starting												FROM PUBLIC
REVOKE ALL ON sp_jobhistory_row_limiter											FROM PUBLIC
REVOKE ALL ON sp_manage_jobs_by_login												FROM PUBLIC
REVOKE ALL ON sp_msx_defect																	FROM PUBLIC
REVOKE ALL ON sp_msx_enlist																	FROM PUBLIC
REVOKE ALL ON sp_multi_server_job_summary										FROM PUBLIC
REVOKE ALL ON sp_post_msx_operation													FROM PUBLIC
REVOKE ALL ON sp_purge_jobhistory														FROM PUBLIC
REVOKE ALL ON sp_remove_job_from_targets										FROM PUBLIC
REVOKE ALL ON sp_resync_targetserver												FROM PUBLIC
REVOKE ALL ON sp_sem_add_message														FROM PUBLIC
REVOKE ALL ON sp_sem_drop_message														FROM PUBLIC
REVOKE ALL ON sp_set_local_time															FROM PUBLIC
REVOKE ALL ON sp_set_sqlagent_properties										FROM PUBLIC
REVOKE ALL ON sp_sqlagent_check_msx_version									FROM PUBLIC
REVOKE ALL ON sp_sqlagent_get_perf_counters									FROM PUBLIC
REVOKE ALL ON sp_sqlagent_get_startup_info									FROM PUBLIC
REVOKE ALL ON sp_sqlagent_has_server_access									FROM PUBLIC
REVOKE ALL ON sp_sqlagent_log_jobhistory										FROM PUBLIC
REVOKE ALL ON sp_sqlagent_notify														FROM PUBLIC
REVOKE ALL ON sp_sqlagent_probe_msx													FROM PUBLIC
REVOKE ALL ON sp_sqlagent_refresh_job												FROM PUBLIC
REVOKE ALL ON sp_start_job																	FROM PUBLIC
REVOKE ALL ON sp_stop_job																		FROM PUBLIC
REVOKE ALL ON sp_target_server_summary											FROM PUBLIC
REVOKE ALL ON sp_uniquetaskname															FROM PUBLIC
REVOKE ALL ON sp_update_alert																FROM PUBLIC
REVOKE ALL ON sp_update_category														FROM PUBLIC
REVOKE ALL ON sp_update_job																	FROM PUBLIC
REVOKE ALL ON sp_update_jobschedule													FROM PUBLIC
REVOKE ALL ON sp_update_jobstep															FROM PUBLIC
REVOKE ALL ON sp_update_notification												FROM PUBLIC
REVOKE ALL ON sp_update_operator														FROM PUBLIC
REVOKE ALL ON sp_update_targetservergroup										FROM PUBLIC
REVOKE ALL ON sp_verify_alert																FROM PUBLIC
REVOKE ALL ON sp_verify_category														FROM PUBLIC
REVOKE ALL ON sp_verify_job																	FROM PUBLIC
REVOKE ALL ON sp_verify_job_date														FROM PUBLIC
REVOKE ALL ON sp_verify_job_identifiers											FROM PUBLIC
REVOKE ALL ON sp_verify_job_time														FROM PUBLIC
REVOKE ALL ON sp_verify_jobproc_caller											FROM PUBLIC
REVOKE ALL ON sp_verify_jobstep															FROM PUBLIC
REVOKE ALL ON sp_verify_notification												FROM PUBLIC
REVOKE ALL ON sp_verify_operator														FROM PUBLIC
REVOKE ALL ON sp_verify_performance_condition								FROM PUBLIC
REVOKE ALL ON sp_verify_subsystem														FROM PUBLIC
END TRY
BEGIN CATCH
END CATCH
go
--remove public permission from Shiloh objects that have been secured in Shiloh and overwritten during instmsdb.sql
--create a temporary table with objects granted to public during execution of instmsdb.sql
CREATE TABLE #instmsdb_public_objects(object_name sysname)

INSERT INTO #instmsdb_public_objects VALUES (N'backupfile')
INSERT INTO #instmsdb_public_objects VALUES (N'backupmediafamily')
INSERT INTO #instmsdb_public_objects VALUES (N'backupmediaset')
INSERT INTO #instmsdb_public_objects VALUES (N'backupset')
INSERT INTO #instmsdb_public_objects VALUES (N'restorehistory')
INSERT INTO #instmsdb_public_objects VALUES (N'restorefile')
INSERT INTO #instmsdb_public_objects VALUES (N'restorefilegroup')
INSERT INTO #instmsdb_public_objects VALUES (N'logmarkhistory')
INSERT INTO #instmsdb_public_objects VALUES (N'suspect_pages')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_get_dtsversion')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_make_dtspackagename')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_add_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_drop_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_reassign_dtspackageowner')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_get_dtspackage')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtspackages')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtspackage_begin')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtspackage_end')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtsstep_begin')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtsstep_end')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_log_dtstask')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtspackagelog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtssteplog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_enum_dtstasklog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtslog_all')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtspackagelog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtssteplog')
INSERT INTO #instmsdb_public_objects VALUES (N'sp_dump_dtstasklog')
go

DECLARE @object_name		  sysname
DECLARE @tsql             nvarchar(300)
DECLARE public_remove_cursor CURSOR LOCAL FOR 
	SELECT object_name FROM #instmsdb_public_objects

OPEN public_remove_cursor
   FETCH NEXT FROM public_remove_cursor INTO @object_name
   WHILE (@@fetch_status = 0)
   BEGIN
      --PRINT @state_desc + N' ' + @permission_name + N' ON ' + @object_name + N' TO ' + @grantee_name
      BEGIN TRY
      --if this object exists in 8.0 msdb and is granted to public no op otherwise remove permission to public on it
        IF (EXISTS (SELECT * FROM msdb.dbo.upgrade_perms 
              WHERE UPPER(object_name collate SQL_Latin1_General_CP1_CS_AS ) = UPPER(@object_name collate SQL_Latin1_General_CP1_CS_AS )))
            AND (NOT EXISTS (SELECT * FROM msdb.dbo.upgrade_perms WHERE object_name = @object_name 
                 AND UPPER(grantee_name collate SQL_Latin1_General_CP1_CS_AS ) = N'PUBLIC'))
          BEGIN
            SELECT @tsql = N'REVOKE ALL ON ' + QUOTENAME(@object_name) + N' FROM PUBLIC'
            PRINT @tsql
            EXEC (@tsql)
          END
      END TRY
      BEGIN CATCH
      END CATCH
      FETCH NEXT FROM public_remove_cursor INTO @object_name
   END
DEALLOCATE public_remove_cursor
go
DROP TABLE #instmsdb_public_objects
DROP TABLE msdb.dbo.upgrade_perms
go

--------------------------------------------------------------------------------
--update proxy account
--proxy update batch
--read sysadminonly flag
DECLARE @ret              INT
DECLARE @proxy_id         INT
DECLARE @job_id           UNIQUEIDENTIFIER
DECLARE @step_id          INT
DECLARE @subsystem        sysname
DECLARE @owner_name       NVARCHAR(256)
DECLARE @full_name        sysname
DECLARE @owner_sid        VARBINARY(85)
DECLARE @is_sysadmin      INT

--walk throu all job steps excluding TSQL jobsteps
DECLARE jobsteps_cursor CURSOR LOCAL FOR
SELECT js.job_id, js.step_id, js.subsystem, SUSER_SNAME(j.owner_sid)
FROM sysjobs j JOIN sysjobsteps js ON j.job_id = js.job_id
WHERE UPPER(js.subsystem collate SQL_Latin1_General_CP1_CS_AS) <> N'TSQL'
AND SUSER_SNAME(j.owner_sid) IS NOT NULL
FOR READ ONLY

--wals thru all non sysadmin job owners
DECLARE job_nonsysadmin_owners_cursor CURSOR LOCAL FOR
SELECT DISTINCT j.owner_sid FROM sysjobs j 
FOR READ ONLY

OPEN job_nonsysadmin_owners_cursor
FETCH NEXT FROM job_nonsysadmin_owners_cursor INTO @owner_sid
WHILE (@@fetch_status = 0)
BEGIN
	SELECT @owner_name = SUSER_SNAME(@owner_sid)
  IF @owner_name IS NOT NULL
  BEGIN
    --is job owner member of sysadmin role?
    BEGIN TRY
      EXECUTE AS LOGIN=@owner_name -- impersonate 
      SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) -- check role membership 
      REVERT -- revert back
    END TRY
    BEGIN CATCH
      SET @is_sysadmin = 0
    END CATCH
          
    IF @is_sysadmin = 0
    BEGIN
	    --add job_owner to the SQLAgentUserRole msdb role in order to permit the job owner to handle his jobs
	    --has this login a user in msdb?
	    IF NOT EXISTS(SELECT * FROM sys.database_principals WHERE sid = @owner_sid)
	    BEGIN
		    PRINT ''
		    PRINT 'Granting login access''' + @owner_name + ''' to msdb database...'
		    BEGIN TRY
		      EXEC sp_grantdbaccess @loginame = @owner_name
        END TRY
        BEGIN CATCH
          RAISERROR('A problem was encountered granting access to MSDB database for login ''%s''. Make sure this login is provisioned with SQLServer and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
        END CATCH		      
	    END

	    PRINT ''
	    PRINT 'Adding user ''' + @owner_name + ''' to SQLAgentUserRole msdb role...'
		  BEGIN TRY
	      EXEC sp_addrolemember @rolename = 'SQLAgentUserRole', @membername = @owner_name
      END TRY
      BEGIN CATCH
        RAISERROR('A problem was encountered adding user ''%s'' to SQLAgentUserRole. Make sure this is a valid user in MSDB database and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
      END CATCH		      
	  END
	END
	FETCH NEXT FROM job_nonsysadmin_owners_cursor INTO @owner_sid
END
DEALLOCATE job_nonsysadmin_owners_cursor
  

--credential created from LSA values in the file src\upgrade_scripts\sqlagent100_upgrade.sql
IF EXISTS (SELECT credential_id FROM master.sys.credentials  WHERE  name = N'UpgradedCredential')
BEGIN
  IF (NOT EXISTS(SELECT * FROM sysproxies WHERE name = N'UpgradedProxyAccount'))
  BEGIN  
    PRINT 'Update proxy account'
    SELECT @ret = 0

    --create the proxy first
    PRINT ''
    PRINT 'Adding Proxy...'
    BEGIN TRY --prevent sp_add_proxy raising severity 16 error that will terminate upgrade scritp when proxy account has bad info
      EXEC @ret = sp_add_proxy @proxy_name      = N'UpgradedProxyAccount',
                                @credential_name = N'UpgradedCredential',
                                @proxy_id        = @proxy_id OUTPUT
    END TRY
    BEGIN CATCH
      SET @ret = 1
    END CATCH      
                              
    IF @ret <> 0
    BEGIN
      RAISERROR('A problem was encountered updating proxy account. Verify that user name and secret of credential [UpgradedCredential] are correct and rerun sqlagent_msdb_upgrade.sql ', 10, 127) WITH LOG
    END
    ELSE
    BEGIN
      OPEN jobsteps_cursor
      FETCH NEXT FROM jobsteps_cursor INTO @job_id, @step_id, @subsystem, @owner_name

      WHILE (@@fetch_status = 0)
      BEGIN
        --is job owner member of sysadmin role?
        BEGIN TRY
          EXECUTE AS LOGIN = @owner_name -- impersonate 
          SELECT @is_sysadmin = ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) -- check role membership 
          REVERT -- revert back
        END TRY
        BEGIN CATCH
          SET @is_sysadmin = 0
        END CATCH
        
        IF @is_sysadmin = 0
        BEGIN        
          IF NOT EXISTS(SELECT * FROM sysproxysubsystem ps JOIN syssubsystems s 
                        ON ps.subsystem_id = s.subsystem_id
                        WHERE s.subsystem = @subsystem
                        AND ps.proxy_id = @proxy_id)
          BEGIN
            PRINT 'Grant permission to proxy ''UpgradedProxyAccount'' for subsystem ''' + @subsystem + '''...'
            BEGIN TRY
              EXEC @ret = sp_grant_proxy_to_subsystem @subsystem_name = @subsystem,
											          @proxy_id       = @proxy_id
					  END TRY
					  BEGIN CATCH
					    SET @ret = 1
					  END CATCH
            IF @ret <> 0
            BEGIN
              RAISERROR('FAILED TO GRANT PERMISSION TO PROXY (%d) FOR SUBSYSTEM ''%s''.', 10, 127, @proxy_id, @subsystem ) WITH LOG
            END
	        END

          IF NOT EXISTS(SELECT * FROM sysproxylogin WHERE proxy_id = @proxy_id AND sid = SUSER_SID(@owner_name))
          BEGIN
            PRINT 'Grant login ''' + @owner_name + '''  permission to use proxy ''UpgradedProxyAccount'' for subsystem ''' + @subsystem + '''...'
            BEGIN TRY
              EXEC @ret = sp_grant_login_to_proxy @proxy_id       = @proxy_id,
                                                  @login_name     = @owner_name
            END TRY
					  BEGIN CATCH
					    SET @ret = 1
					  END CATCH
            IF @ret <> 0
            BEGIN
              RAISERROR('FAILED TO GRANT PERMISSION TO LOGIN ''%s'' FOR PROXY (%d).', 10, 127, @owner_name, @proxy_id) WITH LOG
            END
          END

          --PRINT 'Update sysjobsteps...'
          UPDATE sysjobsteps SET proxy_id = @proxy_id WHERE job_id = @job_id and step_id = @step_id
        END --is_sysadmin = 0
        FETCH NEXT FROM jobsteps_cursor INTO @job_id, @step_id, @subsystem, @owner_name
      END --WHILE (@@fetch_status = 0)
      CLOSE jobsteps_cursor
    END
  END -- NOT EXISTS(SELECT * FROM sysproxies WHERE name = N'UpgradedProxyAccount')
END  -- EXISTS (SELECT credential_id FROM master.sys.credentials  WHERE  name = N'AgentCred80') 
DEALLOCATE jobsteps_cursor                          
go

--msx proxy upgrade
DECLARE @credential_id          INT
--credential created from 80 lSA values in the file src\upgrade_scripts\sqlagent100_upgrade.sql
IF EXISTS (SELECT credential_id FROM master.sys.credentials  WHERE  name = N'UpgradedMSXCredential')
BEGIN

    SELECT @credential_id = credential_id FROM master.sys.credentials
    WHERE  name = N'UpgradedMSXCredential'

    --set credential_id to agent registry
      EXECUTE master.dbo.xp_instance_regwrite  'HKEY_LOCAL_MACHINE',
                                      'SOFTWARE\Microsoft\MSSQLServer\SQLServerAgent',
                                      'MSXCredentialID',
                                      'REG_DWORD', 
                                      @credential_id
END      
go

-- Complete replication job security meta-data upgrades
IF OBJECT_ID('sys.sp_vupgrade_replsecurity_metadata', 'P') IS NOT NULL
BEGIN
	PRINT 'Performing replication job security meta-data upgrades...'
	EXECUTE master.sys.sp_vupgrade_replsecurity_metadata
END
ELSE
BEGIN
	-- "The replication security meta-data could not be upgraded for all database(s). Please ensure that entire server is upgraded and re-execute sp_vupgrade_replsecurity_metadata."
	RAISERROR(21450, 10, -1, 'security meta-data', 'all',  'entire server', 'master.sys.sp_vupgrade_replsecurity_metadata') WITH LOG	
END
GO


-- Log Shipping Upgrade
declare @retcode int
PRINT ''
PRINT 'Upgrading SQL Server Log Shipping...'
exec @retcode = master.sys.sp_upgrade_log_shipping
if @retcode != 0 or @@error != 0
begin
  RAISERROR('Upgrade of Log Shipping for SQL Server did not complete successfully. After upgrade, re-execute sp_upgrade_log_shipping from master database.', 10, 1) WITH LOG
end
PRINT 'Upgraded SQL Server Log Shipping successfully.'
go

-----------------------------------------------------------------------------
--Drop legacy objects
CREATE TABLE #instmsdb_legacy_objects(object_name sysname, type_name sysname, type_id nvarchar(2))
--tables
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.mswebtasks', N'TABLE', N'T' )
--procedures
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_helphistory', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_helptask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_insmswebtask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_purgehistory', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_resync_targetserver', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_sem_get_perf_counter_help', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_updatetask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_updmswebtask', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_verify_jobschedule', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_verifytaskid', N'PROCEDURE', N'P' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sp_check_localserver_name', N'PROCEDURE', N'P' )

--views
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.sysalternates', N'VIEW', N'V' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.systasks', N'VIEW', N'V' )
INSERT INTO #instmsdb_legacy_objects VALUES (N'dbo.systasks_view', N'VIEW', N'V' )
go

DECLARE @object_name		  sysname
DECLARE @type_name		    sysname
DECLARE @type_id 		      nvarchar(2)

DECLARE @tsql             nvarchar(300)
DECLARE legacy_remove_cursor CURSOR LOCAL FOR 
	SELECT object_name, type_name, type_id FROM #instmsdb_legacy_objects

OPEN legacy_remove_cursor
   FETCH NEXT FROM legacy_remove_cursor INTO @object_name, @type_name, @type_id
   WHILE (@@fetch_status = 0)
   BEGIN
      BEGIN TRY
        IF (OBJECT_ID(@object_name, @type_id) IS NOT NULL)
          BEGIN
            SELECT @tsql = N'DROP ' + @type_name + N' ' +  @object_name
            PRINT @tsql
            EXEC (@tsql)
          END
      END TRY
      BEGIN CATCH
      END CATCH
      FETCH NEXT FROM legacy_remove_cursor INTO @object_name, @type_name, @type_id
   END
CLOSE legacy_remove_cursor   
DEALLOCATE legacy_remove_cursor
go
DROP TABLE #instmsdb_legacy_objects
go
--other legacy objects CTP15 to RTM only
BEGIN TRY
if exists (select * from sys.database_principals where name = 'MS_AgentSigningCertificateUser')
   drop user MS_AgentSigningCertificateUser

if exists (select * from sys.server_principals where name = 'MS_AgentSigningCertificateLogin')
   drop login MS_AgentSigningCertificateLogin
   
-- remove the MaintenanceUserRole role CTP15 to RTM only
IF (EXISTS (SELECT *
            FROM msdb.dbo.sysusers
            WHERE (name = N'MaintenanceUserRole')
              AND (issqlrole = 1)))
BEGIN
  BEGIN
    EXECUTE msdb.dbo.sp_droprole @rolename = N'MaintenanceUserRole'
  END
END
END TRY
BEGIN CATCH
END CATCH
go
-------------------------------------------------------------

PRINT '------------------------------------'
PRINT 'Moving 2005 SSIS Data to 2008 tables'
PRINT '------------------------------------'

--
-- Add the old roles to the new SSIS role membership
--

PRINT 'Mapping SSIS yukon roles to katmai roles...'
GO

if exists (select * from dbo.sysusers where [name] = N'db_dtsadmin' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisadmin', N'db_dtsadmin'
END
GO

if exists (select * from dbo.sysusers where [name] = N'db_dtsltduser' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisltduser', N'db_dtsltduser'
END
GO

if exists (select * from dbo.sysusers where [name] = N'db_dtsoperator' and [issqlrole] = 1)
BEGIN
EXEC sp_addrolemember N'db_ssisoperator', N'db_dtsoperator'
END
GO

--
-- Move folders from sysdtspackagefolders90 to sysssispackagefolders
--

PRINT 'Moving package folders...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackagefolders90]') AND type = N'U') 
INSERT INTO [msdb].[dbo].[sysssispackagefolders]
           ([folderid]
           ,[parentfolderid]
           ,[foldername])
    SELECT [folderid]
           ,[parentfolderid]
           ,[foldername]
    FROM [msdb].[dbo].[sysdtspackagefolders90]
    WHERE [folderid] != '00000000-0000-0000-0000-000000000000' -- Root folder
      AND [folderid] != '08aa12d5-8f98-4dab-a4fc-980b150a5dc8' -- Maintenance Plans

GO

--
-- Move packages from sysdtspackages90 to sysssispackages
--

PRINT 'Moving packages...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackages90]') AND type = N'U') 
INSERT INTO [msdb].[dbo].[sysssispackages]
           ([name]
           ,[id]
           ,[description]
           ,[createdate]
           ,[folderid]
           ,[ownersid]
           ,[packagedata]
           ,[packageformat]
           ,[packagetype]
           ,[vermajor]
           ,[verminor]
           ,[verbuild]
           ,[vercomments]
           ,[verid]
           ,[isencrypted]
           ,[readrolesid]
           ,[writerolesid])
    SELECT [name]
           ,[id]
           ,[description]
           ,[createdate]
           ,[folderid]
           ,[ownersid]
           ,[packagedata]
           ,[packageformat]
           ,[packagetype]
           ,[vermajor]
           ,[verminor]
           ,[verbuild]
           ,[vercomments]
           ,[verid]
           ,[isencrypted]
           ,[readrolesid]
           ,[writerolesid]
    FROM [msdb].[dbo].[sysdtspackages90]

GO

--
-- Move log data from sysdtslog90 to sysssislog
--

PRINT 'Moving logs...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') AND type = N'U') 
INSERT INTO [msdb].[dbo].[sysssislog]
           ([event]
           ,[computer]
           ,[operator]
           ,[source]
           ,[sourceid]
           ,[executionid]
           ,[starttime]
           ,[endtime]
           ,[datacode]
           ,[databytes]
           ,[message])
    SELECT [event]
           ,[computer]
           ,[operator]
           ,[source]
           ,[sourceid]
           ,[executionid]
           ,[starttime]
           ,[endtime]
           ,[datacode]
           ,[databytes]
           ,[message]
    FROM [msdb].[dbo].[sysdtslog90]

GO

--
-- Drop yukon objects
--

PRINT 'Dropping yukon stored procedures...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_setpackageroles]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_setpackageroles]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getpackageroles]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_getpackageroles]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_deletepackage]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_deletepackage] 

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getpackage]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_getpackage]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_putpackage]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_putpackage]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_checkexists]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_checkexists]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_listpackages]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_listpackages]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_addlogentry]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_addlogentry]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_deletefolder]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_deletefolder] 

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_addfolder]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_addfolder]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_renamefolder]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_renamefolder]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_getfolder]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_getfolder]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sp_dts_listfolders]') AND type = N'P') 
DROP PROCEDURE [dbo].[sp_dts_listfolders]

GO

PRINT 'Dropping yukon tables...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') AND type = N'U') 
DROP TABLE [dbo].[sysdtslog90]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackages90]') AND type = N'U') 
DROP TABLE [dbo].[sysdtspackages90]

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtspackagefolders90]') AND type = N'U')  
DROP TABLE [dbo].[sysdtspackagefolders90]

GO

--
-- Create a view for the logs table for backwards compatibility
--

PRINT 'Creating sysdtslog90 view...'
GO

IF EXISTS (select * from sys.objects where object_id = object_id(N'[dbo].[sysdtslog90]') and type = N'V')
BEGIN
	DROP VIEW [dbo].[sysdtslog90]
END

GO

CREATE VIEW [dbo].[sysdtslog90]
AS
	SELECT [id]
		  ,[event]
		  ,[computer]
		  ,[operator]
		  ,[source]
		  ,[sourceid]
		  ,[executionid]
		  ,[starttime]
		  ,[endtime]
		  ,[datacode]
		  ,[databytes]
		  ,[message]
	  FROM [msdb].[dbo].[sysssislog]

GO

-------------------------------------------------------------


/*********************************************************************/
/* Create auxilary procedure to enable OBD (Off By Default component */
/*********************************************************************/
IF (OBJECT_ID(N'tempdb..#sp_enable_component', 'P') IS NOT NULL)
BEGIN
    DROP PROCEDURE [tempdb]..[#sp_enable_component]
END
GO 

CREATE PROCEDURE #sp_enable_component     
   @comp_name     sysname, 
   @advopt_old_value    INT OUT, 
   @comp_old_value   INT OUT 
AS
   BEGIN
   SELECT @advopt_old_value=cast(value_in_use as int) from sys.configurations where name = 'show advanced options';
   SELECT @comp_old_value=cast(value_in_use as int) from sys.configurations where name = @comp_name; 
   EXEC sp_configure 'show advanced options',1;
   RECONFIGURE WITH OVERRIDE;
   EXEC sp_configure @comp_name, 1; 
   RECONFIGURE WITH OVERRIDE;
   END
go

IF (OBJECT_ID(N'tempdb..#sp_restore_component_state ', 'P') IS NOT NULL)
BEGIN
    DROP PROCEDURE [tempdb]..[#sp_restore_component_state ]
END
GO 

CREATE PROCEDURE #sp_restore_component_state 
   @comp_name     sysname, 
   @advopt_old_value    INT, 
   @comp_old_value   INT 
AS
   BEGIN
   EXEC sp_configure @comp_name, @comp_old_value; 
   RECONFIGURE WITH OVERRIDE;
   EXEC sp_configure 'show advanced options',@advopt_old_value;
   RECONFIGURE WITH OVERRIDE;
   END
GO


/**************************************************************/
/* DMF Post-upgrade steps                                      */
/**************************************************************/
--
-- >>> CTP5 -> CTP6 Upgrade
--
-- Restoring previously saved data and converting TargetSets to ObjectSets
IF (OBJECT_ID('dbo.dmf_upgrade', 'U') IS NOT NULL)
BEGIN
	BEGIN TRANSACTION 

	-- Restore policies
	SET IDENTITY_INSERT dbo.syspolicy_policies_internal ON
	INSERT dbo.syspolicy_policies_internal (policy_id,name,condition_id,root_condition_id,date_created,execution_mode,policy_category_id,schedule_uid,description,help_text,help_link,is_enabled,job_id,created_by,modified_by,date_modified)
		SELECT policy_id,name,condition_id,root_condition_id,date_created,execution_mode,policy_category_id,schedule_uid,description,help_text,help_link,is_enabled,job_id,created_by,modified_by,date_modified
		FROM msdb.dbo.tmp_syspolicy_policies_internal
	SET IDENTITY_INSERT dbo.syspolicy_policies_internal OFF
	
	-- Restore Health state 
	SET IDENTITY_INSERT dbo.syspolicy_system_health_state_internal ON
	INSERT dbo.syspolicy_system_health_state_internal (health_state_id,policy_id,last_run_date,target_query_expression_with_id,target_query_expression,result)
		SELECT * FROM msdb.dbo.tmp_syspolicy_system_health_state_internal
	SET IDENTITY_INSERT dbo.syspolicy_system_health_state_internal OFF
	
	-- Restore Execution history
	SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_internal ON
	INSERT dbo.syspolicy_policy_execution_history_internal (history_id,policy_id,start_date,end_date,result,is_full_run,exception_message,exception) 
		SELECT * FROM msdb.dbo.tmp_syspolicy_policy_execution_history_internal
	SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_internal OFF

	SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_details_internal ON
	INSERT dbo.syspolicy_policy_execution_history_details_internal (detail_id,history_id,target_query_expression,target_query_expression_with_id,execution_date,result,result_detail,exception_message,exception) 
		SELECT * FROM msdb.dbo.tmp_syspolicy_policy_execution_history_details_internal
	SET IDENTITY_INSERT dbo.syspolicy_policy_execution_history_details_internal OFF
	
	-- Convert TargetSets to ObjectSets
	SET IDENTITY_INSERT dbo.syspolicy_target_sets_internal ON

	DECLARE @policy_id int, @policy_name sysname, @facet nvarchar(max), @os_name sysname, @os_id int, @ts_id int

	DECLARE ts_cur CURSOR FOR
		SELECT p.policy_id, p.name, c.facet, ts.target_set_id
		FROM msdb.dbo.tmp_syspolicy_target_sets_internal ts JOIN dbo.syspolicy_policies p ON (ts.policy_id = p.policy_id)
			JOIN dbo.syspolicy_conditions c ON (p.condition_id = c.condition_id)
		ORDER BY p.policy_id, ts.target_set_id
		
	OPEN ts_cur
	FETCH ts_cur INTO @policy_id , @policy_name , @facet, @ts_id
	WHILE @@FETCH_STATUS = 0
	BEGIN
		-- make sure ObjectSet name is unique
		SET @os_name = LEFT(@policy_name,118) + '_ObjectSet'
		IF EXISTS (SELECT * FROM dbo.syspolicy_object_sets WHERE object_set_name = @os_name)
		BEGIN
			SET @os_name = LEFT(@policy_name,82) + CAST(NEWID() AS nchar(36)) + '_ObjectSet'
		END
		
		-- if we go through multi-TS ObjectSet we only need to add it once
		-- cursor sort order guarantees @os_id remains correct 
		IF 0 = (SELECT ISNULL(object_set_id, 0) FROM syspolicy_policies WHERE policy_id = @policy_id)
		BEGIN
			Exec sp_syspolicy_add_object_set @os_name, @facet, @os_id OUTPUT 
			UPDATE syspolicy_policies_internal
				SET object_set_id = @os_id
				WHERE policy_id = @policy_id
		END
		INSERT syspolicy_target_sets_internal (target_set_id,object_set_id,type_skeleton,type,enabled) 
			SELECT target_set_id,@os_id,type_skeleton,type,1 
			FROM msdb.dbo.tmp_syspolicy_target_sets_internal WHERE target_set_id = @ts_id
		FETCH ts_cur INTO @policy_id , @policy_name , @facet, @ts_id
	END

	CLOSE ts_cur
	DEALLOCATE ts_cur

	SET IDENTITY_INSERT dbo.syspolicy_target_sets_internal OFF

	SET IDENTITY_INSERT dbo.syspolicy_target_set_levels_internal ON
	INSERT syspolicy_target_set_levels_internal (target_set_level_id,target_set_id,type_skeleton,condition_id,level_name)
		SELECT target_set_level_id,target_set_id,type_skeleton,condition_id,level_name 
		FROM msdb.dbo.tmp_syspolicy_target_set_levels_internal

	SET IDENTITY_INSERT dbo.syspolicy_target_set_levels_internal OFF

	-- Add missing levels for MultipartName sets
	DECLARE @tsl_id int
	SET @ts_id = 0
	SET @tsl_id = 0

	DECLARE @mpn_facet_id int
	SELECT @mpn_facet_id = management_facet_id FROM dbo.syspolicy_management_facets 
		WHERE name = 'IMultipartNameFacet'

	DECLARE os_cur CURSOR FOR
		SELECT object_set_id
		FROM dbo.syspolicy_object_sets_internal  
		WHERE facet_id = @mpn_facet_id 

	OPEN os_cur
	FETCH os_cur INTO @os_id
	WHILE @@FETCH_STATUS = 0
	BEGIN
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'PROCEDURE')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/StoredProcedure', @type='PROCEDURE', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/StoredProcedure', @condition_id=NULL, @level_name='StoredProcedure', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'SYNONYM')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/Synonym', @type='SYNONYM', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/Synonym', @condition_id=NULL, @level_name='Synonym', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'TABLE')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/Table', @type='TABLE', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/Table', @condition_id=NULL, @level_name='Table', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'FUNCTION')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/UserDefinedFunction', @type='FUNCTION', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/UserDefinedFunction', @condition_id=NULL, @level_name='UserDefinedFunction', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'TYPE')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/UserDefinedType', @type='TYPE', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/UserDefinedType', @condition_id=NULL, @level_name='UserDefinedType', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'VIEW')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/View', @type='VIEW', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/View', @condition_id=NULL, @level_name='View', @target_set_level_id=@tsl_id  
		END
		IF NOT EXISTS (SELECT * FROM syspolicy_target_sets_internal WHERE object_set_id = @os_id AND type = 'XMLSCHEMACOLLECTION')
		BEGIN
			Exec sp_syspolicy_add_target_set @object_set_id=@os_id, @type_skeleton='Server/Database/XmlSchemaCollection', @type='XMLSCHEMACOLLECTION', @enabled=0, @target_set_id = @ts_id OUTPUT
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database', @condition_id=NULL, @level_name='Database', @target_set_level_id=@tsl_id  
			Exec sp_syspolicy_add_target_set_level @target_set_id = @ts_id, @type_skeleton='Server/Database/XmlSchemaCollection', @condition_id=NULL, @level_name='XmlSchemaCollection', @target_set_level_id=@tsl_id  
		END
		
		FETCH os_cur INTO @os_id
	END

	CLOSE os_cur
	DEALLOCATE os_cur

	-- Clean up upgrade marker
	DROP TABLE dmf_upgrade
	
	-- And temp tables
	DROP TABLE msdb.dbo.tmp_syspolicy_target_sets_internal
	DROP TABLE msdb.dbo.tmp_syspolicy_target_set_levels_internal
	DROP TABLE msdb.dbo.tmp_syspolicy_policies_internal 
	DROP TABLE msdb.dbo.tmp_syspolicy_system_health_state_internal 
	DROP TABLE msdb.dbo.tmp_syspolicy_policy_execution_history_internal 
	DROP TABLE msdb.dbo.tmp_syspolicy_policy_execution_history_details_internal 
	
	COMMIT TRANSACTION
	PRINT 'DMF successfully upgraded' 
END

--
-- <<< CTP5 -> CTP6 Upgrade
--

-- Make sure Agent XPs are enabled regardless of the state of the server
-- We will restove the state afterwards

DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out


-- sproc that creates a job for PBM. This covers the creation of job for all upgrade scenarios.
PRINT 'Executing msdb.dbo.sp_syspolicy_create_purge_job'
EXEC msdb.dbo.sp_syspolicy_create_purge_job

-- Now restore the Agent XPs to their old state
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value

GO


-- Final upgrade step does not depend on any schema changes, and thus can be run for any upgrade

-- Make sure that the policies are using a valid evaluation mode
-- If a policy is using an evaluation mode that is not supported for a facet, then the evaluation mode is None and it is not enabled

UPDATE p
	SET p.execution_mode = 0, p.is_enabled = 0
	FROM 
		[msdb].[dbo].[syspolicy_policies_internal] p 
		INNER JOIN 
		[msdb].[dbo].[syspolicy_conditions] c 
		ON (p.condition_id = c.condition_id)
		INNER JOIN
		[msdb].[dbo].[syspolicy_management_facets] f
		ON (c.facet = f.name)
		WHERE p.execution_mode <> (p.execution_mode & f.execution_mode)

-- Upgrade from CTP5 & CTP6 to RC0 - correct typo in the management facet name
UPDATE [msdb].[dbo].[syspolicy_management_facets]
SET name = 'MessageType' 
WHERE name = 'Messagetype'



		
GO

/**************************************************************/
/* End of DMF Post-upgrade steps                               */
/**************************************************************/

IF (NOT OBJECT_ID(N'tempdb.dbo.#SqlAgentSignatures', 'U') IS NULL)
BEGIN
    DROP TABLE #SqlAgentSignatures
END

-------------------------------------------------------------------------
--
/**************************************************************/
/* Data Collector Post-upgrade steps                          */
/**************************************************************/

DECLARE @advopt_old_value int
DECLARE @comp_old_value int
EXECUTE #sp_enable_component 'Agent XPs', @advopt_old_value out, @comp_old_value out


-- Load the instmdw.sql script into the blob
EXECUTE [dbo].[sp_syscollector_upload_instmdw]

-- Now restore the Agent XPs to their old state
EXECUTE #sp_restore_component_state 'Agent XPs', @advopt_old_value, @comp_old_value

GO
/**************************************************************/
/* End of Data Collector Post-upgrade steps                   */
/**************************************************************/


DROP PROCEDURE #sp_enable_component
DROP PROCEDURE #sp_restore_component_state
GO

PRINT ''
PRINT '-----------------------------------------'
PRINT 'Execution of POSTINSTMSDB100.SQL complete'
PRINT '-----------------------------------------'
go

Print 'Upgrading Database Mail related objects...'

/*
	One of the main functions of this script is to handle migration
	of multiple Mail Host database to a single Mail Host Database in MSDB.
	Pre Beta 3 (CPT 15) versions of SQL Server 2005 allowed 
	Databae Mail object to exist in any database. This script will migrate 
        previously created profile, SentItems and log information to MSDB. 
	Finally the script will remove Database Mail objects in these other databases.

	Another goal of this script is to handle all metadata changes between different
	releases of the product starting with B-2 through subsequent CTPs
*/


USE msdb

SET NOCOUNT ON

-- remove obsolete configuration parameter
IF EXISTS(SELECT * FROM msdb.dbo.sysmail_configuration WHERE paramname = N'MaxNumberOfMailsPerDay')
  DELETE FROM msdb.dbo.sysmail_configuration WHERE paramname=N'MaxNumberOfMailsPerDay'

/*
 	Upgrade objects in MSDB if it was previously used as mailhost database
*/
BEGIN TRY
	IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='profile_name' and id =
			(SELECT OBJECT_ID(N'dbo.sysmail_mailitems', 'U')))
	BEGIN
		  -- convert data from profile_name column to profile_id column
		  exec sp_executesql N'
		  DECLARE @profile_name sysname
		  DECLARE @profile_id int 

		  DECLARE profile_name_cursor CURSOR LOCAL 
		  FOR
			 SELECT sp.profile_id, sp.name
			 FROM dbo.sysmail_profile sp, dbo.sysmail_mailitems mi
			 WHERE sp.name = mi.profile_name AND mi.profile_name IS NOT NULL

		  OPEN profile_name_cursor
		  FETCH NEXT FROM profile_name_cursor INTO @profile_id, @profile_name
		  WHILE (@@fetch_status = 0)
		  BEGIN
			 UPDATE dbo.sysmail_mailitems SET profile_id = @profile_id WHERE profile_name = @profile_name
			 FETCH NEXT FROM profile_name_cursor INTO @profile_id, @profile_name
		  END
		  Close profile_name_cursor
		  DEALLOCATE profile_name_cursor'

		  -- remove obsolete column
		  ALTER TABLE dbo.sysmail_mailitems DROP COLUMN profile_name
	END
END TRY
BEGIN CATCH
	print 'There was a problem upgrading MSDB mail host database.'
	print 'Unable to map existing profile name values to profile_id column'
	print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
	print 'Error Message: ' + ERROR_MESSAGE()
	print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
	print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
GO

if EXISTS(Select * from msdb.dbo.sysmail_principalprofile)
BEGIN
	BEGIN TRY
		-- add existing mail users defined in MSDB to new role
		DECLARE @DBMailUser     sysname
		DECLARE principal_profile_cursor CURSOR LOCAL FOR
				SELECT dp.name FROM dbo.sysmail_principalprofile pp INNER JOIN sys.database_principals dp ON pp.principal_sid = dp.sid and dp.principal_id > 4

		OPEN principal_profile_cursor
		FETCH NEXT FROM principal_profile_cursor INTO @DBMailUser
		WHILE (@@fetch_status = 0)
		BEGIN
			EXEC msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser
			FETCH NEXT FROM principal_profile_cursor INTO @DBMailUser
		END
		CLOSE principal_profile_cursor
		DEALLOCATE principal_profile_cursor
	END TRY
	BEGIN CATCH
		print 'There was a problem upgrading MSDB mail host database.'
		print 'Unable to add existing mail user to DatabaseMailUserRole'
		print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
		print 'Error Message: ' + ERROR_MESSAGE()
		print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
		print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
	END CATCH
END
GO

if EXISTS(Select * from msdb.dbo.sysmail_principalprofile)
BEGIN
	BEGIN TRY
		-- cleaning up database mail related broker conversations
		if( SELECT is_broker_enabled from msdb.sys.databases WHERE name = 'msdb' ) = 0
		BEGIN
			PRINT 'NEED TO RE-ENABLE SSB'
			WHILE(1=1)
			BEGIN
				DECLARE @handle UNIQUEIDENTIFIER
				SET @handle = NULL
				SELECT TOP(1) @handle=conversation_handle FROM msdb.sys.conversation_endpoints
				WHERE (msdb.sys.conversation_endpoints.far_service IN 
							('SQL/Notifications/SysMailNotification/v1.0',
							'ExternalMailService',
							'InternalMailService',
							'SqlQueryNotificationService',
							'iMailRequestorService',
							'iMailResponderService',
							'http://schemas.microsoft.com/SQL/Notifications/EventNotificationService',
							'http://schemas.microsoft.com/SQL/Notifications/PostEventNotification'
							)
						)

				IF @handle IS NULL BREAK
				PRINT 'ENDING CONVERSATION ' + convert(varchar(256),@handle)
				END CONVERSATION @handle WITH CLEANUP
			END
		END

		-- We cannot turn the broker on, because we don't know whether it was disabled by the user
		-- ALTER DATABASE msdb SET ENABLE_BROKER
	END TRY
	BEGIN CATCH
		print 'There was a problem upgrading Mail Host databases.'
		print 'Unable to re-enable server broker. You might need to manually'
		print 'end any pending secure conversations.'
		print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
		print 'Error Message: ' + ERROR_MESSAGE()
		print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
		print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
	END CATCH
END
GO

if EXISTS(SELECT * FROM msdb.dbo.sysmail_principalprofile) AND
   EXISTS(SELECT * FROM msdb.dbo.syscolumns WHERE name='database_id' and id =(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
BEGIN
	/*
 		Handle migration of multiple mail host databases into MSDB
	*/
	BEGIN TRY
		DECLARE @DBName		sysname
		DECLARE @DBNameQuote	sysname
		DECLARE @sql 		nvarchar(max)

		DECLARE @new_mailitem_id 	int
		DECLARE @old_mailitem_id 	int
		DECLARE @profile_name_exists 	bit
		DECLARE @Error			bit
		DECLARE @db_id 			int

		DECLARE  DBName_Cursor CURSOR FOR
			select name from sys.databases WHERE name NOT IN ('msdb', 'tempdb', 'master')
				and HAS_DBACCESS([name]) <> 0

		OPEN DBName_Cursor 

		FETCH NEXT FROM DBName_Cursor INTO @DBName

		WHILE @@FETCH_STATUS = 0
		BEGIN
			Print 'Checking database: ' + @DBName
			SET @DBNameQuote = QUOTENAME(@DBName)
			SELECT @db_id = db_id(@DBName)
			
			IF ( OBJECT_ID(@DBNameQuote + '.dbo.sysmail_log') IS NOT NULL) --Determine if Database Mail objects exist
			BEGIN
				Print @DBName + ' is a MailHost database.'
				
				--Going to migrate profiles from database to MSDB
						DECLARE @DBMailUser				sysname
				DECLARE @sid_MSDB				varbinary(85)
				DECLARE @sid_principal				varbinary(85)
				DECLARE @old_profile_id				int
				DECLARE @new_principal_id			int
				DECLARE @old_principal_id			int
				DECLARE @LoginName					sysname
				
				SET @sql = N'DECLARE  DBMail_Cursor CURSOR FOR
					SELECT p.name
						, pp.profile_id
						, msdb_p.sid
						, p.sid
						, pp.principal_id
					FROM msdb..sysmail_principalprofile pp 
						JOIN '+ @DBNameQuote +'.sys.database_principals p 
							ON pp.principal_id = p.principal_id
						LEFT JOIN msdb.sys.database_principals msdb_p 
							ON p.sid = msdb_p.sid
					where pp.database_id = ' + convert(nvarchar(10),@db_id)
				--print @sql
				EXEC(@sql)

				OPEN DBMail_Cursor

				FETCH NEXT FROM DBMail_Cursor INTO @DBMailUser, @old_profile_id, @sid_MSDB, @sid_principal, @old_principal_id

				WHILE @@FETCH_STATUS = 0
				BEGIN	
					
					Print 'Going to process user: ' + @DBMailUser
				
					IF (@sid_MSDB IS NULL) -- does not already exist in MSDB
					BEGIN
						IF (NOT EXISTS(Select * from sysusers where name = @DBMailUser))
						BEGIN
							IF (EXISTS(Select * from master.dbo.syslogins where sid = @sid_principal))
							BEGIN

								/* Determine the Login Name from the SID	*/
								SELECT @LoginName = name 
								FROM	master.dbo.syslogins
								WHERE	sid = @sid_principal
								
								PRINT 'Add USER to MSDB: ' + @DBMailUser

								SET @sql = N'CREATE USER ' + QUOTENAME(@DBMailUser) + ' FOR LOGIN ' + QUOTENAME(@LoginName)
								EXEC (@sql)
			
								IF (@old_principal_id > 4) -- do not add special accounts such as dbo, public, sys
								BEGIN
									Print 'Grant USER permission to send mail.'
									exec msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser
								END
							END
							ELSE
							BEGIN
								PRINT 'Can not add user as the login does not exist.'
							END
							
						END
						ELSE
						BEGIN
							Print 'User has already been added to MSDB: ' + @DBMailUser
						
							IF (@old_principal_id > 4) -- do not add special accounts such as dbo, public, sys
							BEGIN
								PRINT 'Ensure user has the right to send mail.'
							
								exec msdb..sp_addrolemember @rolename = 'DatabaseMailUserRole',@membername = @DBMailUser

							END

						END


					END
					ELSE
					BEGIN
						Print 'Login already mapped to a user in MSDB'
					END

					IF (EXISTS(Select * from master.dbo.syslogins where sid = @sid_principal))
					BEGIN
						--Get principle_id
						SELECT @new_principal_id = principal_id 
						FROM msdb.sys.database_principals
						Where sid = @sid_principal

						IF (@new_principal_id is not Null)
						BEGIN
							print 'New Principal_id: ' + Convert(varchar(10),@new_principal_id) + '  Old profile_id: ' + convert(varchar(10),@old_profile_id) + '  Old principal id: ' + convert(varchar(10),@old_principal_id)

							SET @sql = N'
							IF NOT EXISTS(select * from msdb..sysmail_principalprofile
											Where profile_id = ' + Convert(varchar(10),@old_profile_id) + '
												AND database_id = 4
												AND principal_id = ' + Convert(varchar(10),@new_principal_id) + ')
							BEGIN
								--Update the Profile
								UPDATE msdb..sysmail_principalprofile
								SET database_id = 4
									, principal_id = ' + Convert(varchar(10),@new_principal_id) + '
								Where profile_id = ' + Convert(varchar(10),@old_profile_id) + '
									AND database_id = ' + Convert(varchar(10),@db_id) + '
									AND principal_id = ' + Convert(varchar(10),@old_principal_id) + '

								IF (@@rowcount = 1)
								BEGIN
									Print ''sysmail_principalprofile updated based on moving user to MSDB.''
								END
							END
							ELSE
							BEGIN
								Print ''This user already has already been configured with this profile in MSDB.''
							END'
							EXEC(@sql)
						END
						ELSE
						BEGIN
							Print 'sysmail_principalprofile table can not be updated for sid: ' + convert(varchar(100),@sid_principal)
						END
					END

					FETCH NEXT FROM DBMail_Cursor INTO @DBMailUser, @old_profile_id, @sid_MSDB, @sid_principal, @old_principal_id
					
				END

				CLOSE DBMail_Cursor
				DEALLOCATE DBMail_Cursor
						
				--/*	Move Data from user Mail Host database to MSDB */
				--Print 'Move Data from user Mail Host database to MSDB.'

				SET @sql = N'DECLARE  mailitem_id_Cursor CURSOR FOR
					SELECT mailitem_id FROM ' + @DBNameQuote + '.dbo.sysmail_mailitems'
				
				EXEC(@sql)
				
				OPEN mailitem_id_Cursor
				
				Set @Error = 0	--Assume no errors

				BEGIN TRANSACTION

				/* Disable Trigger so the "last_mod_date" and "last_mod_user colums" are not updated during transfer. */
				EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_attachments] ON [dbo].[sysmail_attachments]')
				EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_log] ON [dbo].[sysmail_log]')
				EXEC ('DISABLE TRIGGER [dbo].[trig_sysmail_mailitems]ON [dbo].[sysmail_mailitems]')

				Print 'Going to move ALL sysmail_log items not associated with a mailitem'

				SET @sql = N'INSERT INTO msdb.dbo.sysmail_log
					(event_type, log_date, description, process_id, mailitem_id, account_id, last_mod_date, last_mod_user)
					SELECT event_type, log_date, description, process_id, NULL, account_id, last_mod_date, last_mod_user
					FROM '+	@DBNameQuote +'.dbo.sysmail_log
					WHERE mailitem_id IS NULL '
				
				exec(@sql)

				FETCH NEXT FROM mailitem_id_Cursor INTO @old_mailitem_id
				WHILE @@FETCH_STATUS = 0
				BEGIN
					/****************************************/
					/*	MOVE dbo.sysmail_mailitems DATA	*/
					/****************************************/

					/* Need to check the schema defination of the table	*/
					SET @sql = N'USE ' + @DBNameQuote + '
							DECLARE @sql nvarchar(max) 
							IF (EXISTS(select * from syscolumns
							where id = object_id(''[dbo].[sysmail_mailitems]'')
								AND name = ''profile_name''))
							BEGIN						
							SET @sql = N''INSERT INTO msdb.dbo.sysmail_mailitems
							(profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user)
							SELECT CASE WHEN p.profile_id IS NULL THEN -1 ELSE p.profile_id END, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, mi.last_mod_user
							FROM '+	@DBNameQuote +'.dbo.sysmail_mailitems mi LEFT JOIN msdb..sysmail_profile p
								ON mi.profile_name = p.name
							WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id) + ''' 
							END
							ELSE
							BEGIN
							SET @sql = N''INSERT INTO msdb.dbo.sysmail_mailitems
							(profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user)
							SELECT profile_id, recipients, copy_recipients, blind_copy_recipients, subject, body, body_format, importance, sensitivity, file_attachments, attachment_encoding, query, execute_query_database, attach_query_result_as_file, query_result_header, query_result_width, query_result_separator, exclude_query_output, append_query_error, send_request_date, send_request_user, sent_account_id, sent_status, sent_date, last_mod_date, last_mod_user
							FROM '+	@DBNameQuote +'.dbo.sysmail_mailitems 
							WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id) + ''' 
							END

							EXEC(@sql)'

					
					EXEC(@sql)

					IF (@@error <> 0)	--Check for error
					BEGIN
						Set @Error = 1
					END
				
					SELECT @new_mailitem_id = @@identity

					/****************************************/
					/*	MOVE dbo.sysmail_log DATA	*/
					/****************************************/
					SET @sql = N'INSERT INTO msdb.dbo.sysmail_log
							(event_type, log_date, description, process_id, mailitem_id, account_id, last_mod_date, last_mod_user)
							SELECT event_type, log_date, description, process_id, ' + convert(varchar(5),@new_mailitem_id) + ', account_id, last_mod_date, last_mod_user
							FROM '+	@DBNameQuote +'.dbo.sysmail_log
							WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id)
				
					EXEC(@sql)

					IF @@error <> 0 	--Check for error
					BEGIN
						Set @Error = 1
					END

					/****************************************/
					/*	MOVE dbo.sysmail_attachments DATA	*/ 
					/****************************************/
				SET @sql = N'USE ' + @DBNameQuote + ' 
								IF (object_id(''dbo.sysmail_attachments'') IS NOT NULL)
								begin
									INSERT INTO msdb.dbo.sysmail_attachments 
									(mailitem_id, filename, filesize, attachment, last_mod_date, last_mod_user)
									SELECT ' + convert(varchar(5),@new_mailitem_id) + ', filename, filesize, attachment, last_mod_date, last_mod_user
									FROM '+	@DBNameQuote +'.dbo.sysmail_attachments 
									WHERE mailitem_id = ' + CONVERT(VARCHAR(20),@old_mailitem_id)  + '
								end'
					EXEC(@sql)

					IF @@error <> 0 	--Check for error
					BEGIN
						Set @Error = 1
					END


					FETCH NEXT FROM mailitem_id_Cursor INTO @old_mailitem_id
				
				END
			
				IF @Error = 0
				BEGIN
					Print 'Completed data transfer to MSDB.'
					COMMIT TRANSACTION
				END
				ELSE
				BEGIN
					Print 'Not able to complete data transfer to MSDB.'
					ROLLBACK TRANSACTION

				END
			
				/* ENABLE Triggers as they were previously DISABLE	*/
				EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_attachments] ON [dbo].[sysmail_attachments]')
				EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_log] ON [dbo].[sysmail_log]')
				EXEC ('ENABLE TRIGGER [dbo].[trig_sysmail_mailitems]ON [dbo].[sysmail_mailitems]')

				CLOSE mailitem_id_Cursor
				DEALLOCATE mailitem_id_Cursor
				
				IF @Error = 0
				BEGIN
					/**********************************************************************/
					/*                                                                    */
					/* Uninstalls the tables, triggers and stored procedures necessary for*/
					/* sqlimail operations                                                */
					/*                                                                    */
					/*
					** Copyright Microsoft, Inc. 2004
					** All Rights Reserved.
					*/
					/**********************************************************************/
					
					
					
					/**************************************************************/
					--		Drop ALL Database Mail objects (i.e Functions/Procedures )
					/**************************************************************/ 
					
					PRINT ''
					PRINT 'Dropping old Database Mail FUNCTIONS and PROCEDURES ...'
					PRINT ''
					
					-----
					PRINT 'Dropping function ConvertToInt'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.ConvertToInt'', ''FN'') IS NULL
								DROP FUNCTION ConvertToInt')
					
					-----
					PRINT 'Dropping procedure sysmail_start_sp'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_start_sp'', ''P'') IS NULL
						DROP PROCEDURE dbo.sysmail_start_sp')
					
					-----
					PRINT 'Dropping procedure sysmail_stop_sp'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_stop_sp'', ''P'') IS NULL
						DROP PROCEDURE dbo.sysmail_stop_sp')
					
					-----
					PRINT 'Dropping procedure sysmail_logmailevent_sp'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_logmailevent_sp'', ''P'') IS NULL
						DROP PROCEDURE dbo.sysmail_logmailevent_sp')
					
					-----
					PRINT 'Dropping procedure sp_has_changedbuser_permission'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_has_changedbuser_permission'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_has_changedbuser_permission')
					
					-----
					PRINT 'Dropping procedure sp_getprofilerequestxml'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_getprofilerequestxml'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_getprofilerequestxml')
					
					-----
					PRINT 'Dropping procedure sp_sendandreturn'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendandreturn'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_sendandreturn')
					
					-----
					PRINT 'Dropping procedure sp_sendandblock'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendandblock'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_sendandblock')
					
					-----
					PRINT 'Dropping procedure sp_isprohibited'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_isprohibited'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_isprohibited')
					
					-----
					PRINT 'Dropping procedure sp_sendimailqueues'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendimailqueues'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_sendimailqueues')
					
					-----
					PRINT 'Dropping procedure sp_gettestprofilexml'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_gettestprofilexml'', ''P'') IS NULL
					DROP PROCEDURE dbo.sp_gettestprofilexml')
					
					-----
					PRINT 'Dropping procedure sp_testprofileimailqueues'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_testprofileimailqueues'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_testprofileimailqueues')
					
					-----
					PRINT 'Dropping procedure sp_endconversation'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_endconversation'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_endconversation')
					
					-----
					PRINT 'Dropping procedure sp_endconversation'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_endconversation'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_endconversation')
					
					-----
					PRINT 'Dropping procedure sp_readrequest'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_readrequest'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_readrequest')
					
					-----
					PRINT 'Dropping procedure sp_sendresponse'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendresponse'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_sendresponse')
					
					-----
					PRINT 'Dropping procedure sp_sendtestprofileresponse'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_sendtestprofileresponse'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_sendtestprofileresponse')
					
					-----
					PRINT 'Dropping procedure sp_getsendmailxml'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_getsendmailxml'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_getsendmailxml')
					
					-----
					PRINT 'Dropping procedure sendimail_sp'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sendimail_sp'', ''P'') IS NULL
						DROP PROCEDURE dbo.sendimail_sp')
					
					-----
					PRINT 'Dropping procedure sp_testimailprofile'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_testimailprofile'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_testimailprofile')
						
					-----
					PRINT 'Dropping procedure dbo.sp_add_quota_information'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_add_quota_information'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_add_quota_information')
			
					-----
					PRINT 'Dropping procedure dbo.sp_current_principal_mails'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_current_principal_mails'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_current_principal_mails')
			
					-----
					PRINT 'Dropping procedure dbo.sp_delete_quota_information'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_delete_quota_information'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_delete_quota_information')

			
					-----
					PRINT 'Dropping procedure  dbo.sp_ExernalMailQueueListener'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_ExernalMailQueueListener'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_ExernalMailQueueListener')

			
					-----
					PRINT 'Dropping procedure dbo.sp_GetAttachmentData'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_GetAttachmentData'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_GetAttachmentData')

			
					-----
					PRINT 'Dropping procedure dbo.sp_RunMailQuery'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_RunMailQuery'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_RunMailQuery')

			
					-----
					PRINT 'Dropping procedure dbo.sp_SendMailMessage'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_SendMailMessage'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_SendMailMessage')

			
					-----
					PRINT 'Dropping procedure dbo.sp_SendMailQueues'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_SendMailQueues'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_SendMailQueues')
			
					-----
					PRINT 'Dropping procedure dbo.sp_verify_quota_mail_count'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_verify_quota_mail_count'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_verify_quota_mail_count')

					-----
					PRINT 'Dropping procedure dbo.sp_activate_sqlimail'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sp_activate_sqlimail'', ''P'') IS NULL
						DROP PROCEDURE dbo.sp_activate_sqlimail')



			
					
					/**************************************************************/
					--    Drop all Database Mail TABLES 
					/**************************************************************/ 
					
					PRINT ''
					PRINT 'Dropping TABLES...'
					PRINT ''
					
					-----
					PRINT 'Dropping table sysmail_log'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_log'', ''U'') IS NULL
						DROP TABLE sysmail_log')
					
					----- 
					PRINT 'Dropping table sysmail_send_retries'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_send_retries'', ''U'') IS NULL
						DROP TABLE dbo.sysmail_send_retries')
					
					-----
					PRINT 'Dropping table sqlimail_data_transfer'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sqlimail_data_transfer'', ''U'') IS NULL
						DROP TABLE sqlimail_data_transfer')
					
					-----
					PRINT 'Dropping table sysmail_attachments'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_attachments'', ''U'') IS NULL
						DROP TABLE sysmail_attachments')
			
					-----
					PRINT 'Dropping table sysmail_query_transfer'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_query_transfer'', ''U'') IS NULL
						DROP TABLE sysmail_query_transfer')
			
					-----
					PRINT 'Dropping table sysmail_attachments_transfer'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_attachments_transfer'', ''U'') IS NULL
						DROP TABLE sysmail_attachments_transfer')
			
					-----
					PRINT 'Dropping table sysmail_quota_information'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_quota_information'', ''U'') IS NULL
						DROP TABLE sysmail_quota_information')
			
					-----
					PRINT 'Dropping table sysmail_mailitems'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF NOT OBJECT_ID(''dbo.sysmail_mailitems'', ''U'') IS NULL
						DROP TABLE sysmail_mailitems')
			
					
					/**************************************************************/
					--		Drop MESSAGES, CONTRACTS, QUEUES AND SERVICES 
					/**************************************************************/
					
					PRINT ''
					PRINT 'Dropping MESSAGES, CONTRACTS, QUEUES AND SERVICES...'
					PRINT ''
					
					-----
					PRINT 'Dropping service iMailRequestorService'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''iMailRequestorService'')
						DROP SERVICE iMailRequestorService')
					
					-----
					PRINT 'Dropping service iMailResponderService'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''iMailResponderService'')
						DROP SERVICE iMailResponderService')
					
					-----
					PRINT 'Dropping queue iMailRequestor'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailRequestor'' AND type = ''SQ'')
						DROP QUEUE iMailRequestor')
					
					-----
					PRINT 'Dropping queue iMailResponder'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailResponder'' AND type = ''SQ'')
						DROP QUEUE iMailResponder')
					
					-----
					PRINT 'Dropping service [SQL/Notifications/IMailNotification/v1.0]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''SQL/Notifications/IMailNotification/v1.0'')
						DROP SERVICE [SQL/Notifications/IMailNotification/v1.0]')
					   
					-----
					PRINT 'Dropping service [ExternalMailService]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''ExternalMailService'')
						DROP SERVICE [ExternalMailService]')

					-----
					PRINT 'Dropping service [InternalMailService]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.services WHERE name =''InternalMailService'')
						DROP SERVICE [InternalMailService]')

					-----
					PRINT 'Dropping queue iMailNotificationQueue'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS (SELECT * FROM sys.objects WHERE name = ''iMailNotificationQueue'' AND type = ''SQ'')
						DROP QUEUE iMailNotificationQueue')
					   
					-----
					PRINT 'Dropping contract [//www.microsoft.com/imail/contracts/SendMail/v1.0]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_contracts 
							WHERE name = ''//www.microsoft.com/imail/contracts/SendMail/v1.0'')          
						DROP CONTRACT [//www.microsoft.com/imail/contracts/SendMail/v1.0]')
					
					-----
					PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}SendMail]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types 
							WHERE name = ''{//www.microsoft.com/imail/messages}SendMail'')        
					DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}SendMail]')
					  
					-----
					PRINT 'Dropping contract [//www.microsoft.com/imail/contracts/TestProfile/v1.0]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_contracts 
							WHERE name = ''//www.microsoft.com/imail/contracts/TestProfile/v1.0'')         
						DROP CONTRACT [//www.microsoft.com/imail/contracts/TestProfile/v1.0]')
					
					-----
					PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}TestProfile]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types 
							WHERE name = ''{//www.microsoft.com/imail/messages}TestProfile'')        
						DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}TestProfile]')
					
					-----
					PRINT 'Dropping message type [{//www.microsoft.com/imail/messages}TestProfileResponse]'
					-----
					EXEC('USE ' + @DBNameQuote + ' IF EXISTS(SELECT * FROM sys.service_message_types 
							WHERE name = ''{//www.microsoft.com/imail/messages}TestProfileResponse'')
						DROP MESSAGE TYPE [{//www.microsoft.com/imail/messages}TestProfileResponse]')
				
					-----
					PRINT 'Dropping certificates and related users'
					-----
					DECLARE @sqlcmd     nvarchar(max), 
						@CertName       sysname,
						@CertNameQuoted sysname,
						@MailLogin      sysname,
						@MailLoginQuoted sysname    
					
					SELECT @CertName       = N'SQLiMail-Certificate-' + @DBName,
						@CertNameQuoted = QUOTENAME( @CertName,''''),
						@MailLogin      = N'SQLiMail-' + @DBName + '-Certificate-Login',
						@MailLoginQuoted= QUOTENAME( @MailLogin,'''')
					
					-----
					PRINT 'Dropping user in msdb'
					-----
					SET @sqlcmd = 
					N'USE msdb
					IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
						DROP USER ' + QUOTENAME( @MailLogin)
					EXEC sp_executesql @sqlcmd
					
					-----
					PRINT 'Dropping user and certificate login in master'
					-----
					SET @sqlcmd = 
					N'USE master 
						IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
						DROP USER ' + QUOTENAME( @MailLogin) + '
						IF(EXISTS(select * from sys.server_principals where name = N' + @MailLoginQuoted + '))
						DROP LOGIN ' + QUOTENAME( @MailLogin)
					EXEC sp_executesql @sqlcmd
					
					-----
					PRINT 'Dropping user in this database'
					-----
					SET @sqlcmd = 
					N'USE ' + @DBNameQuote + '
					IF(EXISTS (SELECT * FROM sys.database_principals WHERE name = N' + @MailLoginQuoted + '))
						DROP USER ' + QUOTENAME( @MailLogin)

					EXEC sp_executesql @sqlcmd			
					
					-----
					PRINT 'Dropping the certificate in this db'
					-----
					SET @sqlcmd = 
					N'USE ' + @DBNameQuote + '	
					IF(EXISTS(SELECT * FROM sys.certificates WHERE name = N' + @CertNameQuoted + '))
					BEGIN
						DROP CERTIFICATE ' + QUOTENAME(@CertName) + ' 
					END'

					EXEC sp_executesql @sqlcmd			
					
					-----
					PRINT 'Dropping certificate from master'
					-----
					SET @sqlcmd = 
					N'USE master
					IF(EXISTS(SELECT * FROM sys.certificates WHERE name = N' + @CertNameQuoted + '))
						DROP CERTIFICATE ' + QUOTENAME(@CertName)

					EXEC sp_executesql @sqlcmd
				
				END
			END

			FETCH NEXT FROM DBName_Cursor INTO @DBName

		END	-- Loop through all databases.

		CLOSE DBName_Cursor
		DEALLOCATE DBName_Cursor

    	-- deleting all principal associations that are not in MSDB or public
	    exec sp_executesql N'
	    delete from msdb.dbo.sysmail_principalprofile
	    where database_id <> 4 and database_id <> 0'
	END TRY
	BEGIN CATCH
		print 'There was a problem upgrading Mail Host databases.'
		print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
		print 'Error Message: ' + ERROR_MESSAGE()
		print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
		print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
	END CATCH
END

BEGIN TRY
	IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='principal_id' and id =
			(SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
	BEGIN
		-- convert data from principal_id to principal_sid
		exec sp_executesql N'
		DECLARE @principal_sid varbinary(85)
		DECLARE @principal_id int 

		DECLARE principal_sid_cursor CURSOR LOCAL 
		FOR
		SELECT distinct principal_id
		FROM dbo.sysmail_principalprofile

		OPEN principal_sid_cursor 
		FETCH NEXT FROM principal_sid_cursor INTO @principal_id
		WHILE (@@fetch_status = 0)
		BEGIN
			IF @principal_id = 0
			   SET @principal_sid = 0x00
			ELSE
			   SELECT @principal_sid = dbo.get_principal_sid(@principal_id)

			IF @principal_sid IS NOT NULL -- principal_id is valid
			BEGIN
				UPDATE dbo.sysmail_principalprofile
				SET principal_sid = @principal_sid
				WHERE principal_id = @principal_id
			END
			ELSE
			BEGIN
				DELETE FROM dbo.sysmail_principalprofile
				WHERE principal_id = @principal_id
			END
			FETCH NEXT FROM principal_sid_cursor INTO @principal_id
		END
		CLOSE principal_sid_cursor 
		DEALLOCATE principal_sid_cursor'

		-- safety clean-up
		DELETE FROM dbo.sysmail_principalprofile WHERE principal_sid = 0xFFFF

		-- remove obsolete column
		ALTER TABLE dbo.sysmail_principalprofile DROP CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique]
		ALTER TABLE dbo.sysmail_principalprofile DROP COLUMN principal_id
  		ALTER TABLE dbo.sysmail_principalprofile ADD CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique] PRIMARY KEY CLUSTERED ([profile_id] ASC,[principal_sid] ASC)
	END
END TRY
BEGIN CATCH
	print 'There was a problem upgrading MSDB mail host database.'
	print 'Unable to map existing profile id values to profile_sid column'
	print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
	print 'Error Message: ' + ERROR_MESSAGE()
	print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
	print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH
GO

BEGIN TRY
    -- remove database_id column
    IF EXISTS (SELECT * FROM msdb.dbo.syscolumns WHERE name='database_id' and id =
       (SELECT OBJECT_ID(N'dbo.sysmail_principalprofile', 'U')))
    BEGIN
        ALTER TABLE dbo.sysmail_principalprofile DROP CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique]
        ALTER TABLE dbo.sysmail_principalprofile DROP COLUMN database_id
        ALTER TABLE dbo.sysmail_principalprofile ADD CONSTRAINT [SYSMAIL_PRINCIPALPROFILE_ProfilePrincipalMustBeUnique] PRIMARY KEY CLUSTERED ([profile_id] ASC,[principal_sid] ASC)
    END
END TRY
BEGIN CATCH
	print 'There was a problem upgrading MSDB mail host database.'
	print 'Unable to create a primary key constraint on sysmail_principalprofile table'
	print 'Error State: ' + convert(varchar(10),ERROR_STATE() )
	print 'Error Message: ' + ERROR_MESSAGE()
	print 'Error Number: ' + convert(varchar(10),ERROR_NUMBER()) 
	print 'Error Severity: ' + convert(varchar(10),ERROR_SEVERITY())
END CATCH

Print 'Completed upgrade of Database Mail related objects...'
GO
