Almost every shops I’ve worked in, Log Shipping is an important part of their disaster recovery plan (2012 has changed the game with availability groups). When you configure log shipping natively, it also creates a couple of alerts – Log shipping Primary Server Alert and Log shipping Secondary Server Alert (hope you have a SMTP Server and have configured database mail correctly). These alerts are invoked by a job which keeps calling the following stored proc:
exec sys.sp_check_log_shipping_monitor_alert |
It does a fair job of notifying team members (DBAs/System Engineers, etc.) when the log shipping falls behind. Most of these are configurable parameters, and you can also modify these thresholds by updating metadata/system tables (be careful while doing this however)!
I have been in situations where the alert system (SMTP) connectivity stops working (briefly, until restarted), or there are some network connectivity issues. Sometimes with ad-hoc index rebuilds (online rebuilds), I try to keep close eyes on how far behind the log shipping is, without relying heavily on log shipping monitors/alerts. The following combination of T-SQL and PowerShell comes in in the process. With PowerShell, I do not have to run the same query on multiple machines anymore.
What gets called
USE [DBARepo] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO create view [dbo].[DBA_restore_history_checker] as ( SELECT rsh.destination_database_name AS [Database], rsh.user_name AS [Restored By], CASE WHEN rsh.restore_type = 'D' THEN 'Database' WHEN rsh.restore_type = 'F' THEN 'File' WHEN rsh.restore_type = 'G' THEN 'Filegroup' WHEN rsh.restore_type = 'I' THEN 'Differential' WHEN rsh.restore_type = 'L' THEN 'Log' WHEN rsh.restore_type = 'V' THEN 'Verifyonly' WHEN rsh.restore_type = 'R' THEN 'Revert' ELSE rsh.restore_type END AS [Restore Type], rsh.restore_date AS [Restore Started], bmf.physical_device_name AS [Restored From], rf.destination_phys_name AS [Restored To] FROM msdb.dbo.restorehistory rsh INNER JOIN msdb.dbo.backupset bs ON rsh.backup_set_id = bs.backup_set_id INNER JOIN msdb.dbo.restorefile rf ON rsh.restore_history_id = rf.restore_history_id INNER JOIN msdb.dbo.backupmediafamily bmf ON bmf.media_set_id = bs.media_set_id WHERE rsh.restore_date >= DATEADD(dd, ISNULL(-1, -30), GETDATE()) AND destination_database_name = ISNULL('DBName', destination_database_name) ) |
Caller:
foreach ($ServerInstance in get-content "C:\serverlist.txt")
{
##$ServerInstance = "My Hardcoded Server was here. This is commented out."
$Database = "DBARepo"
$ConnectionTimeout = 30
$Query = "select top 1 * from dbo.DBA_restore_history_checker order by [restore started] desc"
$QueryTimeout = 120
$conn=new-object System.Data.SqlClient.SQLConnection
$ConnectionString = "Server={0};Database={1};User Id=username;Password=password;;Connect Timeout={2}" -f $ServerInstance,$Database,$ConnectionTimeout
$conn.ConnectionString=$ConnectionString
$conn.Open()
$cmd=new-object system.Data.SqlClient.SqlCommand($Query,$conn)
$cmd.CommandTimeout=$QueryTimeout
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
$conn.Close()
$ds.Tables
}
As you might have noticed, the above PowerShell script can be used with almost everything, and the best part is that it allows you to iterate through the list of servers you provide.
Happy PowerShelling!