运行sp_replmonitorsubscriptionpendingcmds,将结果以邮件的形式发送告警
sql
$Credential = Get-SQLVaultCredential
$mail_to = "xxx@xxx.com"
$mail_bcc = "xxx@xxx.com"
$mail_from = "xxx@xxx.com"
$mail_subject = "Repl: sp_replmonitorsubscriptionpendingcmds"
$mail_smtpserver = "xxx.xxx.xxx.xxx"
$sql_instances = @"
select CONCAT(ip, ',', port) from dbadmin_ms_instance where enable=1
"@
$sql_get_distdb=@"
SELECT name from sys.databases where is_distributor=1 and DATABASEPROPERTYEX(name, 'Updateability')='READ_WRITE'
"@
$outfile = "$($MyInvocation.MyCommand.Path).log"
if (Test-Path $outfile) {
Remove-Item $outfile
}
$outfile_error = "$($MyInvocation.MyCommand.Path).err"
if (Test-Path $outfile_error) {
Remove-Item $outfile_error
}
$target_db_list=@()
$db_instance_list = Invoke-Sqlcmd -ServerInstance "xxx.xxx.xxx.xxx,1433" -Database DBMonitor -Credential $Credential -TrustServerCertificate -Query $sql_instances
$target_db_list=$db_instance_list | ForEach-Object -Parallel {
try {
$SQL_instance = $_[0]
#Write-Host $SQL_instance
$dbs = Invoke-Sqlcmd -ServerInstance $SQL_instance -Database master -Credential $using:Credential -TrustServerCertificate -Query $using:sql_get_distdb -Verbose -IncludeSqlUserErrors -ErrorAction Stop -OutputSqlErrors $true
$dbs | ForEach-Object {
[PSCustomObject]@{
Instance = $SQL_instance
Database = $_.name
}
}
}
catch {
"$($SQL_instance):$($_.Exception.Message)" | Out-File -FilePath $using:outfile_error -Append
Continue
}
}
$all_pending_cmds_results = @()
foreach ($row in $target_db_list) {
$instance = $row.Instance
$db = $row.Database
#Write-Host "正在连接 [$instance] 上的分发库 [$db] 获取订阅列表..." -ForegroundColor Cyan
try {
# 1. 纯粹获取当前分发库下的所有订阅参数(不包含任何 exec 嵌套)
$sql_get_subscriptions = @"
SELECT DISTINCT
srv_p.srvname AS publisher,
a.publisher_db,
a.publication,
srv_s.srvname AS subscriber,
s.subscriber_db,
s.subscription_type
FROM MSdistribution_agents a
JOIN MSSubscriptions s ON a.id = s.agent_id
JOIN MSreplservers srv_p ON a.publisher_id = srv_p.srvid
JOIN MSreplservers srv_s ON s.subscriber_id = srv_s.srvid
WHERE s.subscriber_db <> 'virtual';
"@
$subscriptions = Invoke-Sqlcmd -ServerInstance $instance -Database $db -Credential $Credential -TrustServerCertificate -Query $sql_get_subscriptions -ErrorAction Stop
if ($subscriptions) {
# 2. 如果存在订阅,在 PowerShell 中一条一条动态拼接并执行
foreach ($sub in $subscriptions) {
# 动态拼接当前的 SQL 命令
$current_cmd = "EXEC sp_replmonitorsubscriptionpendingcmds @publisher='{0}', @publisher_db='{1}', @publication='{2}', @subscriber='{3}', @subscriber_db='{4}', @subscription_type={5};" -f `
$sub.publisher, $sub.publisher_db, $sub.publication, $sub.subscriber, $sub.subscriber_db, $sub.subscription_type
# 【控制台显示】实时输出当前正在执行的命令,方便观察进度
#Write-Host " -> 执行命令: $current_cmd" -ForegroundColor Gray
try {
# 执行该条订阅的积压检查
$res = Invoke-Sqlcmd -ServerInstance $instance -Database $db -Credential $Credential -TrustServerCertificate -Query $current_cmd -ErrorAction Stop
if ($res) {
# 3. 如果有返回结果,将当前实例、数据库和【完整的 SQL 命令】绑定给它
$res | ForEach-Object {
$_ | Add-Member -NotePropertyMembers @{
DistributorInstance = $instance
DistributionDB = $db
ExecutedCommand = $current_cmd # 绑定完整命令文本
} -ErrorAction SilentlyContinue
$all_pending_cmds_results += $_
}
}
}
catch {
Write-Error " 执行单个订阅命令失败: $($_.Exception.Message)"
}
}
}
}
catch {
Write-Error "连接 $instance ($db) 失败: $($_.Exception.Message)"
}
}
#Write-Host "`n--- 所有发布订阅的未同步命令积压结果 ---" -ForegroundColor Green
# ?? 提示:由于 ExecutedCommand 命令很长,使用 -Wrap 可以防止尾部被三个点 (...) 截断
$filtered_results =$all_pending_cmds_results | Where-Object { $_.pendingcmdcount -gt 10 } | Format-Table DistributorInstance, DistributionDB, pendingcmdcount, estimated_time, ExecutedCommand -AutoSize -Wrap
if ($filtered_results) {
$body = $filtered_results| Format-Table DistributorInstance, DistributionDB, pendingcmdcount, estimated_time, ExecutedCommand -AutoSize | Out-String
if ($body) {
Send-MailMessage -To $mail_to -Bcc $mail_bcc -From $mail_from -Subject $mail_subject -Body $body -SmtpServer $mail_smtpserver -Encoding utf8
}
}
if (Test-Path $outfile_error) {
$body_error = get-content -Path $outfile_error -Raw
if ($body_error) {
Send-MailMessage -To $mail_to -From $mail_from -Subject $mail_subject -Body $body_error -SmtpServer $mail_smtpserver -Encoding utf8
}
}