{"id":13174,"date":"2019-12-12T15:02:49","date_gmt":"2019-12-12T14:02:49","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/"},"modified":"2019-12-12T15:02:49","modified_gmt":"2019-12-12T14:02:49","slug":"sql-server-collecting-last-backup-information-in-an-alwayson-environment","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/","title":{"rendered":"SQL Server &#8211; Collecting last backup information in an AlwaysOn environment"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Sometimes you face interesting challenges with unusual environment. One of my customer needed a automated and flexible backup solution. Said like that nothing very complex you will say. But if I mention that some databases were 60TB big with more than 30 filegroups and around 600 database data files each and moreover synchronized in an AlwayOn availability group, it is not the same story and you can easily imagine that working with standard backup strategy will not be viable. Therefore I was working on implementing solution using partial full, partial differential and read-only filegroups backups to minimize the time needed.<br \/>\nWell this post is not explaining the whole solution, but only a way to collect the last backup information of my databases, especially for the ones being in an AlwaysOn availability group and which filegroup states changed.<br \/>\nIf you already worked with partial backups and read-only filegroups backups you know that the backup sequence is very important, but if you don&#8217;t you will quickly notice it if you need to restore, and you can easily understand why this last backup information is crucial. As the backups always have to run on the primary replica, you have to collect the information on all replicas if failover occurred and the primary changed to ensure that you execute the right backups at the right moment and not make unnecessary backups (remember the data volumes).<\/p>\n<p>&nbsp;<\/p>\n<h2>Explanation of the solution and code<\/h2>\n<p>Another thing to mentioned, because of security policies, it was forbidden to use linked server, but hopefully xp_CmdShell was possible. I wanted each replica to work independently, and needed a way to query the remote replicas to collect the last backup information on each SQL Server instances involved. Because backup history might be cleans, I need to store this information in local tables. I created 2 tables, one to stored last database backups information and the other to store last read-only filegroup backups information. Additionally I created 2 tables to collect temporarily the information coming from all replicas.<\/p>\n<p><strong>Creation of the last backup information tables:<\/strong><\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">--########################################################\n--###Backup generator - backup last date info temporary table\n--########################################################\n\nUSE [&lt;YourDatabaseName&gt;]\nGO\n\/*\nif OBJECT_ID('[dbo].[bakgen_backuplastdt_databases_temp]') is not null\n\tdrop table [dbo].[bakgen_backuplastdt_databases_temp]\n*\/\ncreate table [dbo].[bakgen_backuplastdt_databases_temp] (\n\tServerName sysname not null,\n\tSqlInstanceName sysname  not null,\n\tSqlServerName sysname  not null,\n\tServiceBrokerGuid uniqueidentifier not null,\n\tDatabaseCreationDate datetime  not null,\n\tDatabaseName sysname  not null,\n\tBackupType char(1) not null,\n\tLastBackupDate datetime  not null,\n\tLastBackupSize numeric(20,0) not null,\n\tis_primary bit null,\n\tinsertdate datetime  not null\n)\nGO\ncreate unique clustered index idx_bakgen_backuplastdt_databases_temp on [dbo].[bakgen_backuplastdt_databases_temp](DatabaseCreationDate,DatabaseName,BackupType,ServerName,SqlInstanceName)\n\n\n\n--########################################################\n--###Backup generator - backup last date info\n--########################################################\n\nUSE [&lt;YourDatabaseName&gt;]\nGO\n\/*\nif OBJECT_ID('[dbo].[bakgen_backuplastdt_databases]') is not null\n\tdrop table [dbo].[bakgen_backuplastdt_databases]\n*\/\ncreate table [dbo].[bakgen_backuplastdt_databases] (\n\tServerName sysname  not null,\n\tSqlInstanceName sysname  not null,\n\tSqlServerName sysname  not null,\n\tServiceBrokerGuid uniqueidentifier not null,\n\tDatabaseCreationDate datetime  not null,\n\tDatabaseName sysname  not null,\n\tBackupType char(1) not null,\n\tLastBackupDate datetime  not null,\n\tLastBackupSize numeric(20,0) not null,\n\tis_primary bit null,\n\tinsertdate datetime  not null\n)\nGO\ncreate unique clustered index idx_bakgen_backuplastdt_databases on [dbo].[bakgen_backuplastdt_databases](DatabaseCreationDate,DatabaseName,BackupType,ServerName,SqlInstanceName)\n<\/pre>\n<p>I finally decided to work with a stored procedure calling a PowerShell scripts to remotely execute the queries on the replicas.<br \/>\nThe stored procedure lists the existing replicas and collects the last database backup information, then the read-only filegroup backup information creating 2 different queries to execute locally on the server and store the data in the temp tables first. It will create similar queries, excluding the databases not involved in availability groups and execute them on the remote replicas using xp_CmdShell running PowerShell scripts. The PowerShell scripts are dynamically created using the TSQL queries generated. They used one function of the well-known DBATools. So you will have to install it first.<br \/>\nYou will notice that in order to log the scripts generated are nicely formatted in order to read and debug them easier. But before executing you PowerShell script through xp_CmdShell you need to apply some string formatting like the 2 lines I added to avoid the execution to fail:<\/p>\n<p>set @PSCmd = replace(replace(@PSCmd, nchar(13), N&#8221;), nchar(10), N&#8217; &#8216;)<br \/>\nset @PSCmd = replace(@PSCmd, &#8216;&gt;&#8217;, N&#8217;^&gt;&#8217;)<\/p>\n<p>Do not forget to escape some characters, otherwise the execution will fails, in my case omitting to escape the &#8216;&gt;&#8217; sign raise an &#8220;Access is denied&#8221; message in the output of the xp_CmdShell execution.<\/p>\n<p>After that the code is comparing what has been collected in the temp tables with the final information and update information if needed.<\/p>\n<p><strong>Here is the complete code of the stored procedure:<\/strong><\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\nuse [&lt;YourDatabaseName&gt;]\nif OBJECT_ID('dbo.bakgen_p_getbakinfo') is not null\n            drop procedure dbo.bakgen_p_getbakinfo \ngo\n\nCREATE PROCEDURE dbo.bakgen_p_getbakinfo \nAS\n\/************************************\n*   dbi-services SA, Switzerland    *\n*   https:\/\/www.dbi-services.com        *\n*************************************\n    Group\/Privileges..: DBA\n    Script Name......:       bakgen_p_getbakinfo.sql\n    Author...........:          Christophe Cosme\n    Date.............:           2019-09-20\n    Version..........:          SQL Server 2016 \/ 2017\n    Description......:        Get the backup information locally but also on the replica involved\n\n    Input parameters.: \n\n            Output parameter: \n                                               \n    Called by........:         Stored Procdedure : [dbo].[bakgen_p_bakexe]\n************************************************************************************************\n    Historical\n    Date        Version    Who    Whats                  Comments\n    ----------  -------    ---    --------    -----------------------------------------------------\n    2019-09-30  1.0        CHC    Creation\n************************************************************************************************\/ \nBEGIN \n\nBEGIN TRY\n            \n            set nocount on\n\n            declare \n    @ErrorMessage  NVARCHAR(4000), \n    @ErrorSeverity INT, \n    @ErrorState    INT;\n\n            declare @ModuleName sysname,\n                                    @ProcName sysname,\n                                    @InfoLog nvarchar(max),\n                                    @Execute char(1)\n                        \n            set @ModuleName = 'BakGen'\n            set @ProcName = OBJECT_NAME(@@PROCID)\n            set @Execute = 'A'\n\n            set @InfoLog = 'Retrieve backup information'\n            execute dbo.bakgen_p_log       \n                        @ModuleName = @ModuleName,\n                        @ProcedureName = @ProcName,\n                        @ExecuteMode = @Execute,\n                        @LogType = 'INFO',\n                        @DatabaseName = null,\n                        @Information = @InfoLog,\n                        @Script = null\n\n\n            --###variable to store error message\n            declare @errmsg varchar(4000)\n            --###variable with the current datetime\n            declare @cdt datetime = getdate()\n\n            --###variabler to store the sql and powershell commands to execute\n            declare @sqllocalDB nvarchar(4000),\n                                    @sqllocalFG nvarchar(4000),\n                                    @sqlremoteDB nvarchar(4000),\n                                    @sqlremoteFG nvarchar(4000),\n                                    @PSCmd nvarchar(4000)\n\n            --###variable to store the local SQL server name\n            declare @LocalSqlServerName sysname\n            --###variable to store the list of replicas\n            declare @TAgReplica table (AgReplicaName sysname)\n            --###variable for the cursors\n            declare @AgReplicaName sysname\n\n            --###set the local SQL Server name\n            set @LocalSqlServerName = lower(convert(sysname,serverproperty('ServerName')))\n                        \n\n            --############################################################################\n            --### check if tables exist\n            --############################################################################\n            if object_id('[dbo].[bakgen_backuplastdt_databases_temp]') is null\n            begin\n                        set @errmsg = 'Get Backup info : table not found'\n                        set @errmsg += '          table name = [dbo].[bakgen_backuplastdt_databases_temp]' \n                        raiserror (@errmsg,11,1);\n            end\n            if object_id('[dbo].[bakgen_backuplastdt_fgreadonly_temp]') is null\n            begin\n                        set @errmsg = 'Get Backup info : table not found'\n                        set @errmsg += '          table name = [dbo].[bakgen_backuplastdt_fgreadonly_temp]' \n                        raiserror (@errmsg,11,1);                      \n            end\n\n            if object_id('[dbo].[bakgen_backuplastdt_databases]') is null\n            begin\n                        set @errmsg = 'Get Backup info : table not found'\n                        set @errmsg += '          table name = [dbo].[bakgen_backuplastdt_databases]' \n                        raiserror (@errmsg,11,1);\n            end\n            if object_id('[dbo].[bakgen_backuplastdt_fgreadonly]') is null\n            begin\n                        set @errmsg = 'Get Backup info : table not found'\n                        set @errmsg += '          table name = [dbo].[bakgen_backuplastdt_fgreadonly]' \n                        raiserror (@errmsg,11,1);                      \n            end\n\n\n            \n            --############################################################################\n            --### select the replicas involved adding first the local server\n            --############################################################################\n            insert into @TAgReplica (AgReplicaName ) select @LocalSqlServerName\n\n            --###check if alwayson feature is activated\n            if (serverproperty('IsHadrEnabled') = 1)\n            begin\n                        insert into @TAgReplica (AgReplicaName )\n                        select lower(agr.replica_server_name) from sys.availability_replicas agr\n                                    where agr.replica_server_name &lt;&gt; @LocalSqlServerName\n            end\n\n\n            --############################################################################\n            --### construct the SQL command to execute on the local SQL Server\n            --############################################################################\n            set @sqllocalDB = ''\n            set @sqllocalDB +='\n\n            declare @Tbi table (\n                        ServerName sysname,\n                        SqlInstanceName sysname,\n                        SqlServerName sysname,\n                        ServiceBrokerGuid uniqueidentifier,\n                        DatabaseCreationDate datetime,\n                        DatabaseName sysname,\n                        BackupType char(1),\n                        LastBackupDate datetime,\n                        is_primary bit null,\n                        insertdate datetime       \n            )\n\n\n            insert into @Tbi (\n                        [ServerName],\n                        [SqlInstanceName],\n                        [SqlServerName],\n                        [ServiceBrokerGuid],\n                        [DatabaseCreationDate],\n                        [DatabaseName],\n                        [BackupType],\n                        [LastBackupDate],\n                        [is_primary],\n                        [insertdate])\n            select  \n                        lower(convert(sysname,serverproperty(''machinename''))) as ServerName,\n                        lower(convert(sysname,serverproperty(''InstanceName''))) as SqlInstanceName,\n                        lower(convert(sysname,serverproperty(''ServerName''))) as SqlServerName,\n                        db.service_broker_guid as ServiceBrokerGuid,\n                        db.create_date as DatabaseCreationDate,\n                        bs.database_name as DatabaseName,\n                        bs.type as BackupType,\n                        max(bs.backup_finish_date) as LastBackupDate,\n                        sys.fn_hadr_is_primary_replica(bs.database_name) as is_primary,\n                        ''' + convert(varchar,@cdt,120) + '''   \n            from msdb.dbo.backupset bs\n                        inner join sys.databases db on db.name = bs.database_name\n                        where bs.type in (''D'',''I'',''P'',''Q'')\n                                    and bs.is_copy_only = 0\n                                    and coalesce(sys.fn_hadr_is_primary_replica(bs.database_name),-1) in (-1,0,1)\n                        group by\n                                    db.service_broker_guid,\n                                    db.create_date,\n                                    bs.database_name,\n                                    bs.type, \n                                    sys.fn_hadr_is_primary_replica(bs.database_name)\n\n            insert into [dbo].[bakgen_backuplastdt_databases_temp] (\n                        [ServerName],\n                        [SqlInstanceName],\n                        [SqlServerName],\n                        [ServiceBrokerGuid],\n                        [DatabaseCreationDate],\n                        [DatabaseName],\n                        [BackupType],\n                        [LastBackupDate],\n                        [LastBackupSize],\n                        [is_primary],\n                        [insertdate])\n            select  \n                        t.[ServerName],\n                        t.[SqlInstanceName],\n                        t.[SqlServerName],\n                        t.[ServiceBrokerGuid],\n                        t.[DatabaseCreationDate],\n                        t.[DatabaseName],\n                        t.[BackupType],\n                        t.[LastBackupDate],\n                        bs.[backup_size],\n                        t.[is_primary],\n                        t.[insertdate]\n            from @Tbi t\n                        inner join msdb.dbo.backupset bs on \n                                    bs.backup_finish_date = t.LastBackupDate  \n                                    and bs.database_name collate database_default = t.DatabaseName collate database_default\n                                    and bs.type collate database_default = t.BackupType collate database_default\n'\n\n\n\n\n            set @sqllocalFG = ''\n            set @sqllocalFG +='\n\n            insert into [dbo].[bakgen_backuplastdt_fgreadonly_temp]\n           ([ServerName],\n           [SqlInstanceName],\n           [SqlServerName],\n                           [ServiceBrokerGuid],\n                           [DatabaseCreationDate],\n           [DatabaseName],\n           [BackupType],\n           [filegroup_name],\n           [file_logicalname],\n           [filegroup_guid],\n           [file_guid],\n           [LastBackupDate],\n                           [LastBackupReadOnlyLsn],\n           [is_primary],\n                           [insertdate])\n            select  \n                        lower(convert(sysname,serverproperty(''machinename''))) as ServerName,\n                        lower(convert(sysname,serverproperty(''InstanceName''))) as SqlInstanceName,\n                        lower(convert(sysname,serverproperty(''ServerName''))) as SqlServerName,\n                        db.service_broker_guid as ServiceBrokerGuid,\n                        db.create_date as DatabaseCreationDate,\n                        bs.database_name as DatabaseName,\n                        bs.type as BackupType,\n                        bf.filegroup_name,\n                        bf.logical_name as file_logicalname,\n                        bf.filegroup_guid,\n                        bf.file_guid,\n                        max(bs.backup_finish_date) as LastBackupDate,\n                        max(bf.read_only_lsn) as LastBackupReadOnlyLsn,\n                        sys.fn_hadr_is_primary_replica(bs.database_name) as is_primary, \n                        ''' + convert(varchar,@cdt,120) + '''   \n            from msdb.dbo.backupset bs\n                                    inner join msdb.dbo.backupfile bf on  bf.backup_set_id = bs.backup_set_id\n                                    inner join sys.databases db on db.name = bs.database_name \n                        where \n                                    bs.backup_finish_date &gt;= db.create_date \n                                    and bs.type in (''F'')\n                                    and bs.is_copy_only = 0\n                                    and coalesce(sys.fn_hadr_is_primary_replica(bs.database_name),-1) in (-1,0,1)\n                                    and bf.is_present = 1\n                                    and bf.is_readonly = 1\n                                    and bf.file_type = ''D''\n                        group by\n                                    db.service_broker_guid,\n                                    db.create_date,\n                                    bs.database_name, \n                                    bs.type,\n                                    bf.filegroup_name,\n                                    bf.logical_name, \n                                    bf.filegroup_guid,\n                                    bf.file_guid,\n                                    sys.fn_hadr_is_primary_replica(bs.database_name)\n'\n\n\n            \n            --############################################################################\n            --### construct the SQL command to execute on the remote SQL Server\n            --############################################################################\n            set @sqlremoteDB = ''\n            set @sqlremoteDB +='\n\n            declare @Tbi table (\n                        ServerName sysname,\n                        SqlInstanceName sysname,\n                        SqlServerName sysname,\n                        ServiceBrokerGuid uniqueidentifier,\n                        DatabaseCreationDate datetime, \n                        DatabaseName sysname,\n                        BackupType char(1),\n                        LastBackupDate datetime,\n                        is_primary bit null,\n                        insertdate datetime       \n            )\n\n            insert into @Tbi (\n                        [ServerName],\n                        [SqlInstanceName],\n                        [SqlServerName],\n                        [ServiceBrokerGuid],\n                        [DatabaseCreationDate],\n                        [DatabaseName],\n                        [BackupType],\n                        [LastBackupDate],\n                        [is_primary],\n                        [insertdate])\n            select  \n                        lower(convert(sysname,serverproperty(''machinename''))) as ServerName,\n                        lower(convert(sysname,serverproperty(''InstanceName''))) as SqlInstanceName,\n                        lower(convert(sysname,serverproperty(''ServerName''))) as SqlServerName,\n                        db.service_broker_guid as ServiceBrokerGuid,\n                        db.create_date as DatabaseCreationDate,\n                        bs.database_name as DatabaseName,\n                        bs.type as BackupType,\n                        max(bs.backup_finish_date) as LastBackupDate,\n                        sys.fn_hadr_is_primary_replica(bs.database_name) as is_primary, \n                        ''' + convert(varchar,@cdt,120) + '''     \n            from msdb.dbo.backupset bs\n                        inner join sys.databases db on db.name = bs.database_name \n                        where bs.type in (''D'',''I'',''P'',''Q'')\n                                    and bs.is_copy_only = 0\n                                    and coalesce(sys.fn_hadr_is_primary_replica(bs.database_name),-1) in (0,1)\n                        group by\n                                    db.service_broker_guid,\n                                    db.create_date,\n                                    bs.database_name,\n                                    bs.type,\n                                    sys.fn_hadr_is_primary_replica(bs.database_name) \n\n            select  \n                        t.[ServerName],\n                        t.[SqlInstanceName],\n                        t.[SqlServerName],\n                        t.[ServiceBrokerGuid],\n                        t.[DatabaseCreationDate],\n                        t.[DatabaseName],\n                        t.[BackupType],\n                        t.[LastBackupDate],\n                        bs.[backup_size],\n                        t.[is_primary],\n                        t.[insertdate]\n            from @Tbi t\n                        inner join msdb.dbo.backupset bs on \n                                    bs.backup_finish_date = t.LastBackupDate \n                                    and bs.database_name collate database_default = t.DatabaseName collate database_default\n                                    and bs.type collate database_default = t.BackupType collate database_default\n\n'\n\n            set @sqlremoteFG = ''\n            set @sqlremoteFG +='\n\n            select  \n                        lower(convert(sysname,serverproperty(''machinename''))) as ServerName,\n                        lower(convert(sysname,serverproperty(''InstanceName''))) as SqlInstanceName,\n                        lower(convert(sysname,serverproperty(''ServerName''))) as SqlServerName,\n                        db.service_broker_guid as ServiceBrokerGuid,\n                        db.create_date as DatabaseCreationDate,\n                        bs.database_name as DatabaseName,\n                        bs.type as BackupType,\n                        bf.filegroup_name,\n                        bf.logical_name as file_logicalname,\n                        bf.filegroup_guid,\n                        bf.file_guid,\n                        max(bs.backup_finish_date) as LastBackupDate,\n                        max(bf.read_only_lsn) as LastReadOnlyLsn,\n                        sys.fn_hadr_is_primary_replica(bs.database_name) as is_primary, \n                        ''' + convert(varchar,@cdt,120) + '''   \n            from msdb.dbo.backupset bs\n                                    inner join msdb.dbo.backupfile bf on  bf.backup_set_id = bs.backup_set_id\n                                    inner join sys.databases db on db.name = bs.database_name \n                        where \n                                    bs.backup_finish_date &gt;= db.create_date \n                                    and bs.type in (''F'')\n                                    and bs.is_copy_only = 0\n                                    and coalesce(sys.fn_hadr_is_primary_replica(bs.database_name),-1) in (0,1)\n                                    and bf.is_present = 1\n                                    and bf.is_readonly = 1\n                                    and bf.file_type = ''D''\n                        group by\n                                    db.service_broker_guid,\n                                    db.create_date, \n                                    bs.database_name, \n                                    bs.type,\n                                    bf.filegroup_name,\n                                    bf.logical_name, \n                                    bf.filegroup_guid,\n                                    bf.file_guid,\n                                    sys.fn_hadr_is_primary_replica(bs.database_name) \n'\n\n            --############################################################################\n            --### delete all records in the backup info tables\n            --############################################################################\n            delete from [dbo].[bakgen_backuplastdt_databases_temp]\n            delete from [dbo].[bakgen_backuplastdt_fgreadonly_temp]\n\n            --############################################################################\n            --### loop for all replicas involved\n            --############################################################################\n            declare cur_replica cursor\n            static local forward_only\n            for \n                        select AgReplicaName\n                        from @TAgReplica\n                 \n            open cur_replica\n            fetch next from cur_replica into \n                        @AgReplicaName                    \n\n\n            while @@fetch_status = 0\n            begin \n                                    \n                        if @LocalSqlServerName = @AgReplicaName\n                        begin \n\n                                    set @InfoLog = 'Get database backup information on local SQL Server instance ' + QUOTENAME(@AgReplicaName)\n                                    execute dbo.bakgen_p_log       \n                                               @ModuleName = @ModuleName,\n                                               @ProcedureName = @ProcName,\n                                                @ExecuteMode = @Execute,\n                                               @LogType = 'INFO',\n                                               @DatabaseName = null,\n                                               @Information = @InfoLog,\n                                               @Script = @sqllocalDB\n                                    execute sp_executesql @sqllocalDB\n\n                                    set @InfoLog = 'Get read-only filegroup backup information on local SQL Server instance ' + QUOTENAME(@AgReplicaName)\n                                    execute dbo.bakgen_p_log       \n                                               @ModuleName = @ModuleName,\n                                               @ProcedureName = @ProcName,\n                                               @ExecuteMode = @Execute,\n                                               @LogType = 'INFO',\n                                               @DatabaseName = null,\n                                               @Information = @InfoLog,\n                                               @Script = @sqllocalFG\n                                    execute sp_executesql @sqllocalFG\n\n                        end \n                        else\n                        begin\n                                    --############################################################################\n                                    --### construct the PowerShell command to execute on the remote SQL Server\n                                    --############################################################################\n                                    set @PSCmd  = ''\n                                    set @PSCmd += 'PowerShell.exe '\n                                    set @PSCmd += '-Command \"'\n                                    set @PSCmd += '$qrydb = \"' + @sqlremoteDB + '\"; ' \n                                    set @PSCmd += '$qryfg = \"' + @sqlremoteFG + '\"; ' \n                                    set @PSCmd += '$rdb = Invoke-DbaQuery -SqlInstance ' + @AgReplicaName + ' -Query $qrydb; '\n                                    set @PSCmd += '$rfg = Invoke-DbaQuery -SqlInstance ' + @AgReplicaName + ' -Query $qryfg; '\n                                    set @PSCmd += 'if ($rdb -ne $null) { '\n                                    set @PSCmd += 'Write-DbaDbTableData -SqlInstance ' + @LocalSqlServerName + ' -Database ' + db_name() + ' -Schema dbo -Table bakgen_backuplastdt_databases_temp -InputObject $rdb;'\n                                    set @PSCmd += '} '\n                                    set @PSCmd += 'if ($rfg -ne $null) { '\n                                    set @PSCmd += 'Write-DbaDbTableData -SqlInstance ' + @LocalSqlServerName + ' -Database ' + db_name() + ' -Schema dbo -Table bakgen_backuplastdt_fgreadonly_temp -InputObject $rfg;'\n                                    set @PSCmd += '} '\n                                    set @PSCmd += '\"'\n\n                                    set @InfoLog = 'Get backup information on replica SQL Server instance ' + QUOTENAME(@AgReplicaName) + ' executing master..xp_cmdshell PowerShell script'\n                                    execute dbo.bakgen_p_log       \n                                               @ModuleName = @ModuleName,\n                                               @ProcedureName = @ProcName,\n                                               @ExecuteMode = @Execute,\n                                               @LogType = 'INFO',\n                                               @DatabaseName = null,\n                                               @Information = @InfoLog,\n                                               @Script = @PSCmd\n\n                                    --###remove CRLF for xp_cmdshell and PowerShell \n                                    set @PSCmd = replace(replace(@PSCmd, nchar(13), N''), nchar(10), N' ')\n                                    set @PSCmd = replace(@PSCmd, '&gt;', N'^&gt;')\n                                    --###Execute the powershell command on the replica and store the result in the temporary tables\n                                    exec master..xp_cmdshell @PSCmd\n                        end\n                        \n                        fetch next from cur_replica into \n                                    @AgReplicaName                    \n\n\n            end\n            close cur_replica\n            deallocate cur_replica\n\n\n            --############################################################################\n            --### Update and insert backup information in final tables\n            --############################################################################\n\n            --###Update first the database creation date with the local ones\n            Update t\n                        set t.DatabaseCreationDate = db.create_date\n            from [dbo].[bakgen_backuplastdt_databases_temp] t\n                        inner join sys.databases db \n                                    on db.name collate database_default = t.DatabaseName collate database_default \n                                               and db.service_broker_guid = t.ServiceBrokerGuid\n\n            Update t\n                        set t.DatabaseCreationDate = db.create_date\n            from [dbo].[bakgen_backuplastdt_fgreadonly_temp] t\n                        inner join sys.databases db \n                                    on db.name collate database_default = t.DatabaseName collate database_default \n                                               and db.service_broker_guid = t.ServiceBrokerGuid\n\n\n\n\n            BEGIN TRY\n\n                        begin transaction \n\n                        delete f\n                                    from [dbo].[bakgen_backuplastdt_databases_temp] t\n                                               inner join [dbo].[bakgen_backuplastdt_databases] f \n                                                           on f.DatabaseCreationDate = t.DatabaseCreationDate\n                                                                       and f.DatabaseName = t.DatabaseName \n                                                                       and f.BackupType = t.BackupType \n                                                                       and f.ServerName = t.ServerName \n                                                                       and t.SqlInstanceName = f.SqlInstanceName\n                                               where f.LastBackupDate &lt; t.LastBackupDate\n\n                        Insert into [dbo].[bakgen_backuplastdt_databases] (\n                                    ServerName,\n                                    SqlInstanceName,\n                                    SqlServerName,\n                                    DatabaseCreationDate,\n                                    DatabaseName,\n                                    BackupType,\n                                    LastBackupDate,\n                                    LastBackupSize,\n                                    is_primary,\n                                    insertdate \n                        )\n                        select \n                                    t.ServerName,\n                                    t.SqlInstanceName,\n                                    t.SqlServerName,\n                                    t.DatabaseCreationDate,\n                                    t.DatabaseName,\n                                    t.BackupType,\n                                    t.LastBackupDate,\n                                    t.LastBackupSize,\n                                    t.is_primary,\n                                    t.insertdate \n                                    from [dbo].[bakgen_backuplastdt_databases_temp] t\n                                               where not exists (select 1 from [dbo].[bakgen_backuplastdt_databases] f \n                                                                                                                      where f.DatabaseName = t.DatabaseName \n                                                                                                                                  and f.BackupType = t.BackupType \n                                                                                                                                  and f.ServerName = t.ServerName \n                                                                                                                                  and t.SqlInstanceName = f.SqlInstanceName)\n                                    \n                        \n                        commit\n\n                        begin transaction\n\n                        delete f\n                                    from [dbo].[bakgen_backuplastdt_fgreadonly_temp] t\n                                               inner join [dbo].[bakgen_backuplastdt_fgreadonly] f \n                                                           on f.DatabaseName = t.DatabaseName \n                                                                       and f.BackupType = t.BackupType \n                                                                       and f.filegroup_name = t.filegroup_name\n                                                                       and f.ServerName = t.ServerName \n                                                                       and f.SqlInstanceName = t.SqlInstanceName\n                                               where f.LastBackupDate &lt; t.LastBackupDate\n\n\n                        Insert into [dbo].[bakgen_backuplastdt_fgreadonly] (\n                                    ServerName,     \n                                    SqlInstanceName,\n                                    SqlServerName,           \n                                    DatabaseCreationDate,\n                                    DatabaseName,            \n                                    BackupType,\n                                    filegroup_name,\n                                    file_logicalname,          \n                                    filegroup_guid, \n                                    file_guid,          \n                                    LastBackupDate,          \n                                    LastBackupReadOnlyLsn,\n                                    is_primary,\n                                    insertdate                     \n                        )\n                        select \n                                    t.ServerName,   \n                                    t.SqlInstanceName,\n                                    t.SqlServerName,\n                                    t.DatabaseCreationDate,\n                                    t.DatabaseName,          \n                                    t.BackupType,\n                                    t.filegroup_name,\n                                    t.file_logicalname,        \n                                    t.filegroup_guid,           \n                                    t.file_guid,        \n                                    t.LastBackupDate,        \n                                    t.LastBackupReadOnlyLsn,\n                                    t.is_primary,\n                                    t.insertdate                   \n                        from [dbo].[bakgen_backuplastdt_fgreadonly_temp] t                                        \n                                    where not exists (\n                                               select 1 from  [dbo].[bakgen_backuplastdt_fgreadonly] f \n                                               where f.DatabaseName = t.DatabaseName \n                                                                       and f.BackupType = t.BackupType \n                                                                       and f.filegroup_name = t.filegroup_name\n                                                                       and f.ServerName = t.ServerName \n                                                                       and t.SqlInstanceName = f.SqlInstanceName)\n\n                        \n                        commit\n            END TRY\n            BEGIN CATCH\n                SELECT \n                                    @ErrorMessage = ERROR_MESSAGE(), \n                                    @ErrorSeverity = ERROR_SEVERITY(), \n                                    @ErrorState = ERROR_STATE();\n\n                        IF @@TRANCOUNT &gt; 0\n                                    ROLLBACK\n                        \n                        raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);\n\n            END CATCH\n\n\n\nRETURN;\n\nEND TRY\nBEGIN CATCH\n    SELECT \n        @ErrorMessage = ERROR_MESSAGE(), \n        @ErrorSeverity = ERROR_SEVERITY(), \n        @ErrorState = ERROR_STATE();\n\n            set @InfoLog = '@ErrorState = ' + convert(nvarchar, @ErrorState) + '\/@ErrorSeverity = ' + convert(nvarchar, @ErrorSeverity) + '\/@ErrorMessage = ' + @ErrorMessage\n            execute dbo.bakgen_p_log       \n                        @ModuleName = @ModuleName,\n                        @ProcedureName = @ProcName,\n                        @ExecuteMode = @Execute,\n                        @LogType = 'ERROR',\n                        @DatabaseName = null,\n                        @Information = @InfoLog,\n                        @Script = null\n\n    raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);\nEND CATCH;\n\nRETURN\nEND<\/pre>\n<h2>Other Objects needed<\/h2>\n<p>As mentioned above I used the DBATools Write-DbaDbTableData function, so need to install it before being able to run the above stored procedure.<\/p>\n<p>I share also the 2 other objects used in the above stored procedure, but of course you can adapt the code to your needs<\/p>\n<p><strong>Creation of the log table:<\/strong><\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">--########################################################\n--###Backup generator - logs\n--########################################################\n\nUSE [&lt;YourDatabaseName&gt;]\nGO\n\/*\nif OBJECT_ID('[dbo].[bakgen_logs]') is not null\n\tdrop table [dbo].[bakgen_logs]\n*\/\ncreate table [dbo].[bakgen_logs] (\n\tid bigint identity(1,1) not null,\n\tLogDate datetime,\n\tSqlServerName sysname,\n\tModuleName sysname,\n\tProcedureName sysname,\n\tExecuteMode char(1),\n\tLogType nvarchar(50),\n\tDatabaseName sysname null,\n\tInformation nvarchar(max) null,\n\tScripts nvarchar(max) null,\nCONSTRAINT [PK_bakgen_logs] PRIMARY KEY CLUSTERED \n(\n\t[id] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]\n)\nGO\n<\/pre>\n<p><strong>Creation of the stored procedure to write the logs:<\/strong><\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">use [&lt;YourDatabaseName&gt;]\nif OBJECT_ID('dbo.bakgen_p_log') is not null\n\tdrop procedure dbo.bakgen_p_log \ngo\n\nCREATE PROCEDURE dbo.bakgen_p_log \n(\n\t@ModuleName sysname,\n\t@ProcedureName sysname,\n\t@ExecuteMode char(1),\n\t@LogType nvarchar(50),\n\t@DatabaseName sysname = null,\n\t@Information nvarchar(max) =  null,\n\t@Script nvarchar(max)  = null\n)\n\nAS\n\/************************************\n*   dbi-services SA, Switzerland    *\n*   https:\/\/www.dbi-services.com        *\n*************************************\n    Group\/Privileges..: DBA\n    Script Name......:\tbakgen_p_log.sql\n    Author...........:\tChristophe Cosme\n    Date.............:\t2019-09-20\n    Version..........:\tSQL Server 2016 \/ 2017\n    Description......:\twrite information to the log table to keep trace of the step executed\n\n    Input parameters.: \n\n\tOutput parameter: \n\t\t\t\t\n************************************************************************************************\n    Historical\n    Date        Version    Who    Whats\t\tComments\n    ----------  -------    ---    --------\t-----------------------------------------------------\n    2019-10-14  1.0        CHC    Creation\n************************************************************************************************\/ \nBEGIN \n\nBEGIN TRY\n\t\n\t--###variable to store error message\n\tdeclare @errmsg varchar(4000)\n\n\tif OBJECT_ID('[dbo].[bakgen_logs]') is null\n\tbegin\n\t\tset @errmsg = 'bakgen_p_log : table not found - be sure the table exists'\n\t\tset @errmsg += '\ttable name = [dbo].[bakgen_logs]' \n\t\traiserror (@errmsg,11,1);\n\tend\t\t\n\n\tinsert into [dbo].[bakgen_logs] (\n\t\tLogDate,\n\t\tSqlServerName,\n\t\tModuleName,\n\t\tProcedureName,\n\t\tExecuteMode,\n\t\tLogType,\n\t\tDatabaseName,\n\t\tInformation,\n\t\tScripts\n\t\t)\n\tvalues(\n\t\tgetdate(),\n\t\tconvert(sysname,SERVERPROPERTY('servername')),\n\t\t@ModuleName,\n\t\t@ProcedureName,\n\t\t@ExecuteMode,\n\t\t@LogType,\n\t\t@DatabaseName,\n\t\t@Information,\n\t\t@Script\n\t\t)\n\n\nRETURN;\n\nEND TRY\nBEGIN CATCH\n\tdeclare \n    @ErrorMessage  NVARCHAR(4000), \n    @ErrorSeverity INT, \n    @ErrorState    INT;\n    SELECT \n        @ErrorMessage = ERROR_MESSAGE(), \n        @ErrorSeverity = ERROR_SEVERITY(), \n        @ErrorState = ERROR_STATE();\n \n    -- return the error inside the CATCH block\n    raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);\nEND CATCH;\n\nRETURN\nEND\n<\/pre>\n<h2>Conclusion<\/h2>\n<p>Triggering PowerShell from a stored procedure did the trick for my special case and is very practical. But to find the right syntax to make the script running through xp_CmdShell was not so trivial. I admit to spend sometimes to figure out what was causing the issue.<br \/>\nBut I definitely enjoyed the solution for retrieving information outside the local SQL Server instance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Sometimes you face interesting challenges with unusual environment. One of my customer needed a automated and flexible backup solution. Said like that nothing very complex you will say. But if I mention that some databases were 60TB big with more than 30 filegroups and around 600 database data files each and moreover synchronized in [&hellip;]<\/p>\n","protected":false},"author":38,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229,198,99],"tags":[466,1781,202,1782,1783,272,51,1784,1785],"type_dbi":[],"class_list":["post-13174","post","type-post","status-publish","format-standard","hentry","category-database-administration-monitoring","category-database-management","category-sql-server","tag-alwayson","tag-availability-group","tag-backup","tag-filegroup-backup","tag-partial-backup","tag-powershell","tag-sql-server","tag-strored-procedure","tag-xp_cmdshell"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SQL Server - Collecting last backup information in an AlwaysOn environment - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server - Collecting last backup information in an AlwaysOn environment\" \/>\n<meta property=\"og:description\" content=\"Introduction Sometimes you face interesting challenges with unusual environment. One of my customer needed a automated and flexible backup solution. Said like that nothing very complex you will say. But if I mention that some databases were 60TB big with more than 30 filegroups and around 600 database data files each and moreover synchronized in [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-12-12T14:02:49+00:00\" \/>\n<meta name=\"author\" content=\"Christophe Cosme\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Christophe Cosme\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\"},\"author\":{\"name\":\"Christophe Cosme\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a\"},\"headline\":\"SQL Server &#8211; Collecting last backup information in an AlwaysOn environment\",\"datePublished\":\"2019-12-12T14:02:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\"},\"wordCount\":724,\"commentCount\":0,\"keywords\":[\"AlwaysOn\",\"Availability group\",\"Backup\",\"Filegroup backup\",\"Partial backup\",\"PowerShell\",\"SQL Server\",\"Strored Procedure\",\"xp_CmdShell\"],\"articleSection\":[\"Database Administration &amp; Monitoring\",\"Database management\",\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\",\"name\":\"SQL Server - Collecting last backup information in an AlwaysOn environment - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"datePublished\":\"2019-12-12T14:02:49+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server &#8211; Collecting last backup information in an AlwaysOn environment\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a\",\"name\":\"Christophe Cosme\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g\",\"caption\":\"Christophe Cosme\"},\"description\":\"Christophe Cosme has more than 22 years of experience in architecture, development and implementation of IT solutions including 17 years in the Business Intelligence area as well as 10 years of experience working with the Microsoft SQL Server Business Intelligence suite. His experience and qualifications cover project management, business analysis, functional and technical requirements. His expertise also includes the implementation of IT solutions in national as well as international organizations. Christophe Cosme is Expert in MS SQL Server DB Engine, SSIS, SSAS, SSRS and PowerBI. Prior to joining dbi services, Christophe Cosme was Solution Lead Business Intelligence Diabetes Care at Hoffmann-La-Roche Ltd in Basel . He also worked as Senior Manager Head of Business Intelligence for Swiss International Airlines Ltd. Christophe Cosme holds a Master's degree in Engineering, Automation from the IT\u2013 ENSISA (F). His branch-related experience covers pharmaceuticals, IT and the airline sector.\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/christophe-cosme\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SQL Server - Collecting last backup information in an AlwaysOn environment - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server - Collecting last backup information in an AlwaysOn environment","og_description":"Introduction Sometimes you face interesting challenges with unusual environment. One of my customer needed a automated and flexible backup solution. Said like that nothing very complex you will say. But if I mention that some databases were 60TB big with more than 30 filegroups and around 600 database data files each and moreover synchronized in [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/","og_site_name":"dbi Blog","article_published_time":"2019-12-12T14:02:49+00:00","author":"Christophe Cosme","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Christophe Cosme","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/"},"author":{"name":"Christophe Cosme","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a"},"headline":"SQL Server &#8211; Collecting last backup information in an AlwaysOn environment","datePublished":"2019-12-12T14:02:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/"},"wordCount":724,"commentCount":0,"keywords":["AlwaysOn","Availability group","Backup","Filegroup backup","Partial backup","PowerShell","SQL Server","Strored Procedure","xp_CmdShell"],"articleSection":["Database Administration &amp; Monitoring","Database management","SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/","url":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/","name":"SQL Server - Collecting last backup information in an AlwaysOn environment - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2019-12-12T14:02:49+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-collecting-last-backup-information-in-an-alwayson-environment\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"SQL Server &#8211; Collecting last backup information in an AlwaysOn environment"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/5cbf7c261d165a45977c85f535d6cb6a","name":"Christophe Cosme","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/736ec7a3216e381c2ef81f210f381e613297d76c2120169411c4423c3c58992c?s=96&d=mm&r=g","caption":"Christophe Cosme"},"description":"Christophe Cosme has more than 22 years of experience in architecture, development and implementation of IT solutions including 17 years in the Business Intelligence area as well as 10 years of experience working with the Microsoft SQL Server Business Intelligence suite. His experience and qualifications cover project management, business analysis, functional and technical requirements. His expertise also includes the implementation of IT solutions in national as well as international organizations. Christophe Cosme is Expert in MS SQL Server DB Engine, SSIS, SSAS, SSRS and PowerBI. Prior to joining dbi services, Christophe Cosme was Solution Lead Business Intelligence Diabetes Care at Hoffmann-La-Roche Ltd in Basel . He also worked as Senior Manager Head of Business Intelligence for Swiss International Airlines Ltd. Christophe Cosme holds a Master's degree in Engineering, Automation from the IT\u2013 ENSISA (F). His branch-related experience covers pharmaceuticals, IT and the airline sector.","url":"https:\/\/www.dbi-services.com\/blog\/author\/christophe-cosme\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/13174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=13174"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/13174\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=13174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=13174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=13174"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=13174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}