CiAgICA8IS0tIExpbmtlZEluIC0tPgogICAgPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogICAgICAgIF9saW5rZWRpbl9wYXJ0bmVyX2lkID0gIjEyMzUwNzMiOwogICAgICAgIHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyA9IHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyB8fCBbXTsKICAgICAgICB3aW5kb3cuX2xpbmtlZGluX2RhdGFfcGFydG5lcl9pZHMucHVzaChfbGlua2VkaW5fcGFydG5lcl9pZCk7CiAgICA8L3NjcmlwdD48c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgICAgICAgKGZ1bmN0aW9uKCl7dmFyIHMgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0IilbMF07CiAgICAgICAgICAgIHZhciBiID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7CiAgICAgICAgICAgIGIudHlwZSA9ICJ0ZXh0L2phdmFzY3JpcHQiO2IuYXN5bmMgPSB0cnVlOwogICAgICAgICAgICBiLnNyYyA9ICJodHRwczovL3NuYXAubGljZG4uY29tL2xpLmxtcy1hbmFseXRpY3MvaW5zaWdodC5taW4uanMiOwogICAgICAgICAgICBzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGIsIHMpO30pKCk7CiAgICA8L3NjcmlwdD4KICAgIDxub3NjcmlwdD4KICAgICAgICA8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjEiIHN0eWxlPSJkaXNwbGF5Om5vbmU7IiBhbHQ9IiIgc3JjPSJodHRwczovL3B4LmFkcy5saW5rZWRpbi5jb20vY29sbGVjdC8/cGlkPTEyMzUwNzMmZm10PWdpZiIgLz4KICAgIDwvbm9zY3JpcHQ+CiAgICA8IS0tIEVuZCBMaW5rZWRJbiAtLT4KICAgIA==
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Dynamische Publisher Jobs über CustomApp

Mit DeltaMaster Publisher steht ein großartiges Werkzeug zur Verfügung, um Berichte aktuell und zielgruppenorientiert zu erzeugen und bereitzustellen. Standardberichte werden in der Regel zu definierten Zeitpunkten erstellt und verschickt. Trotzdem gibt es immer wieder die Anforderung, ad hoc einen Bericht oder eine Berichtsgruppe zu versenden. Jedoch ist der Publisher nicht immer bei den Anwendern installiert oder die IT kann nicht zeitnah unterstützen. Für diesen Fall wird in diesem Blogbeitrag erläutert, wie einzelne Jobs dynamisch aus DeltaMaster heraus über den SQL Server-Agent angestoßen werden können.

Das Grundgerüst

Zunächst werden die für diese Aktion grundsätzlichen, notwendigen Berechtigungen und Bestand-teile veranschaulicht.

Custom App Berechtigungen

Da der Aufruf aus DeltaMaster über die CustomApp heraus erfolgt, muss die Nutzung der CustomApp generell aktiviert sein. Über die Tabelle „T_SYS_CustomApp_Rights“ kann die Ausfüh-rung der einzelnen Menüeinträge, die im CustomApp Menü erscheinen, für einzelne Benutzer oder Benutzerrollen erteilt oder verweigert werden. Weiterhin müssen die Benutzer für P_APP Prozeduren berechtigt werden, also die im Menüpunkt verwendeten P_APP_Select_ und die aufgerufenen P_APP Prozeduren.

Datenbank Berechtigungen

In diesem Schritt werden die notwendigen User und Gruppen angelegt und in den entsprechenden Bereichen berechtigt.

Windows Berechtigungen

Zunächst wird empfohlen, eine Windows Benutzergruppe einzurichten, damit später ggf. weitere User einfach hinzugefügt werden können.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Lokale-Gruppen.pngAbbildung 1: Lokale Gruppe anlegen

Danach werden die entsprechenden AD-User dieser Gruppe hinzugefügt.

SQL Server Berechtigungen

Im nächsten Schritt wird diese Gruppe dem SQL Server als Login bekannt gemacht und in der msdb Datenbank in die Rolle „SQLAgentOperatorRole“ aufgenommen. Da hier dynamisch Jobs erstellt und gelöscht werden sollen, reichen die Rollen „SQLAgentReaderRole“ oder „SQLAgentUserRole“ nicht aus. Eine exaktere Differenzierung lässt Microsoft hier leider nicht zu.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_SQL-Server-Login.png

Abbildung 2: SQL Server Login Informationen

Microsoft empfiehlt für den SQL Server-Agent die Verwendung eines Proxys. Hier wird zur Vereinfachung DeltaMaster Service User (bc-hsg-lap\dmrs) verwendet. Zunächst muss dieser User jedoch in einer neuen Anmeldeinformation hinterlegt werden.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Neue-Anmeldeinformation-Proxy.png

Abbildung 3: Neue Anmeldeinformation für Proxy

Unter dem Menüpunkt SQL Server-Agent/Proxy/Betriebssystem (CmdExec) wird schließlich ein neues Proxy Konto eingerichtet und die obige Anmeldeinformation diesem Konto zugeordnet.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Zuordnung-Proxykonto.png

Abbildung 4: Zuordnung Anmeldeinformation zu Proxykonto

Repository Berechtigungen

Nun muss die Gruppe noch im Repository hinzugefügt und den Rollen „Berichtsverteilung ausführen“ und „Berichtsverteilung definieren“ zugeordnet werden.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Berechtigungen-Repository.png

Abbildung 5: Berechtigungen in der Repository Verwaltung

Der verwendete DeltaMaster Service User muss natürlich noch in den betroffenen Datenbanken berechtigt werden. Bei der hier verwendeten Chair und in der Publisher Datenbank reichen Leserechte aus. In der Repository Datenbank sind „db_owner“ Rechte notwendig.

Prozeduren und Logik

Zunächst wird eine P_APP_Select_Job Prozedur erstellt, die die vorhandenen Jobs aus dem Publisher ausliest und in DeltaMaster zur Auswahl anbietet. Alternativ könnten hier auch Jobgruppen abgefragt werden.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_1.5-Code-Prozeduren-und-Logik.png

CREATE PROC [dbo].[P_APP_SELECT_Job] 
AS 

BEGIN 

SELECT 
[JobID]	AS PublisherJobID, 
[Description]	AS JobName 
FROM 
DeltaMasterPublisher.dbo.Job 
ORDER BY 1 
END  

Danach wird im SQL Server-Agent mit dem Aufruf des DeltaMaster Publishers via „Ausführen als” unter dem angelegten Proxy ein generischer Job erstellt und der Code dazu wird als Skript im SQL Server Management Studio ausgegeben.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Neuer-Job-SQL-Server-Agent.png

Abbildung 6: Neuer Job im SQL Server-Agent

Dieses Grundgerüst wird nun etwas „getunt“, damit generische Jobs mit Übergabe der Publisher JobID und eindeutigen Namen erzeugt werden können.

Daher werden einige Variablen benötigt, die den Zeitstempel und den User angeben, um daraus den eindeutigen Job Namen zu erstellen.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_2.5-Code-Prozeduren-und-Logik.png

DECLARE @Zeitstempel SMALLDATETIME = GETDATE(); 
DECLARE @JobStarter	 NVARCHAR(MAX) = SUSER_NAME(); 
DECLARE @JobName	 NVARCHAR(MAX) = CONCAT(N'BerichtsversandManuell', '_', @JobStarter, '_', @Zeitstempel);  

Danach wird der starre Aufruf des Publishers mit einer fixen Jobnummer auf einen dynamischen Aufruf mit Übergabe der JobID aus der CustomApp geändert.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_3.5-Code-Prozeduren-und-Logik.png

DECLARE @Command	 NVARCHAR(MAX) = N'"C:\Program Files (x86)\DeltaMaster
6\DeltaMaster.Publisher.exe" ' + @PublisherJobID; 

Als nächstes wird noch ein Aufruf zum Starten des Jobs benötigt und über eine While Schleife mit Abfrage in der msdb wird überprüft, ob der Job beendet ist.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_4.5-Code-Prozeduren-und-Logik.png

EXEC msdb.dbo.sp_start_job @JobName; 

DECLARE @Job_UID UNIQUEIDENTIFIER; 
SELECT @Job_UID = job_id 
FROM msdb.dbo.sysjobs 
WHERE name = @JobName; 

WHILE ( 
      ( 
          SELECT COUNT(*) 
          FROM msdb.dbo.sysjobactivity 
          WHERE job_id = @Job_UID 
                AND stop_execution_date IS NOT NULL 
      ) < 1 
      ) 
BEGIN 
    WAITFOR DELAY '00:00:01'; 
END; 

Abschließend muss der Job dann noch nach Beendigung gelöscht werden.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_5.5-Code-Prozeduren-und-Logik.png

EXEC msdb.dbo.sp_delete_job @job_name = @JobName;

Dieser ganze Code kurz zusammengefasst ergibt folgendes Skript:

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_1.3-Code-Prozeduren-und-Logik.png

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_2.3-Code-Prozeduren-und-Logik.png

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_3.3-Code-Prozeduren-und-Logik.png

CREATE PROC [dbo].[P_APP_StartPublisherJob_SQLAgent] 
(@PublisherJobID VARCHAR(MAX)) 
AS 
DECLARE @Zeitstempel SMALLDATETIME = GETDATE(); 
DECLARE @JobStarter	 NVARCHAR(MAX) = SUSER_NAME(); 
DECLARE @JobName	 NVARCHAR(MAX) = CONCAT(N'BerichtsversandManuell', '_', @JobStarter, '_', @Zeitstempel); 
DECLARE @Command	 NVARCHAR(MAX) = N'"C:\Program Files (x86)\DeltaMaster
6\DeltaMaster.Publisher.exe" ' + @PublisherJobID; 

BEGIN TRANSACTION; 
DECLARE @ReturnCode INT; 
SELECT @ReturnCode = 0; 

IF NOT EXISTS 

( 
    SELECT name 
    FROM msdb.dbo.syscategories 
    WHERE name = N'[Uncategorized (Local)]' 
          AND category_class = 1 
) 
BEGIN 
    EXEC @ReturnCode = msdb.dbo.sp_add_category @class = N'JOB', 
                                                @type = N'LOCAL', 
                                                @name = N'[Uncategorized (Local)]'; 
    IF (@@ERROR <> 0 OR @ReturnCode <> 0) 
        GOTO QuitWithRollback; 
END; 

DECLARE @jobId BINARY(16); 
EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name = @JobName, 
                                       @enabled = 1, 
                                       @notify_level_eventlog = 0, 
                                       @notify_level_email = 0, 
                                       @notify_level_netsend = 0, 
                                       @notify_level_page = 0, 
                                       @delete_level = 0, 
                                       @description = N'Keine Beschreibung verfügbar.', 
                                       @category_name = N'[Uncategorized (Local)]', 
                                       @owner_login_name = N'BC\huesgen', 
                                       @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'Berichtsversand', 
                                           @step_id = 1, 
                                           @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'CmdExec', 
                                           @command = @Command, 
                                           @flags = 0, 
                                           @proxy_name = N'DMSQLAgentProxyKonto'; 
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 = N'(local)'; 
IF (@@ERROR <> 0 OR @ReturnCode <> 0) 
    GOTO QuitWithRollback; 
COMMIT TRANSACTION; 
GOTO EndSave; 
QuitWithRollback: 
IF (@@TRANCOUNT > 0) 
    ROLLBACK TRANSACTION; 
EndSave: 

EXEC msdb.dbo.sp_start_job @JobName; 

DECLARE @Job_UID UNIQUEIDENTIFIER; 
SELECT @Job_UID = job_id 
FROM msdb.dbo.sysjobs 
WHERE name = @JobName; 

WHILE ( 
      ( 
          SELECT COUNT(*) 
          FROM msdb.dbo.sysjobactivity 
          WHERE job_id = @Job_UID 
                AND stop_execution_date IS NOT NULL 
      ) < 1 
      ) 
BEGIN 
    WAITFOR DELAY '00:00:01'; 
END; 

EXEC msdb.dbo.sp_delete_job @job_name = @JobName; 

Konfiguration CustomApp

Zur generellen Konfiguration und den vielfältigen Optionen der CustomApp sei hiermit auf den hervorragenden Blogbeitrag „CustomApp Teil1 - Anwendung im Client“ verwiesen.

Der Menüeintrag wird erzeugt, indem die gewünschten Texte und Parameter in die Tabelle „T_SYS_CustomAppMenue“ eingetragen werden. Der Subtype = 2 (Synchroner Aufruf einer Prozedur mit Parametern ohne Transaktion) wird ausgewählt und in der Spalte Criteria1 steht der Name der Prozedur, die den Job erzeugt.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Eintraege-Menue.png

Abbildung 7: Einträge „T_SYS_CustomAppMenue“

In die dazugehörige Parameter Tabelle wird eingetragen, welche Prozedur die Combobox mit Inhalten füllt (Spalte SQLCommand) und welcher Parameter an die Prozedur übergeben werden soll (ParameterID).

Weiterhin ist die Spalte InputType = 2 wichtig, da dies eine Combobox ohne zusätzliche freie Eingabemöglichkeit erzeugt.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Eintraege-Parameter.png

Abbildung 8: Einträge „ T_SYS_CustomAppMenue_ProcParameters“

Über die Tabelle „T_SYS_CustomApp_Rights“ wird festgelegt, welcher User/Rolle welchen Menüeintrag nutzen darf.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_Eintraege-Rights.png

Abbildung 9: Einträge „ T_SYS_CustomApp_Rights“

Aufruf in DeltaMaster

Nun wird betrachtet, wie der Aufruf aus DeltaMaster aussieht.

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_DeltaMaster-Custom-App.png

Abbildung 10: DeltaMaster CustomApp Menü

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_DeltaMaster-CustomApp-Liste.png

Abbildung 11: DeltaMaster Auswahlliste

2020-11-06_Crew_Dynamische-Publisher-Jobs-ueber-Custom-App_DeltaMaster-CustomApp-Ergebnis.png

Abbildung 12: DeltaMaster Ergebnis

Damit steht dem Anwender nun eine komfortable und dynamische Möglichkeit zur Verfügung, um Publisher Jobs zu starten. Das Prinzip lässt sich beliebig erweitern, um beispielsweise Datenladeprozesse oder Aufbereitungsprozesse anzustoßen, außerhalb der regulären fest definierten Nachtprozesse.