SQL Server sp_replmonitorsubscriptionpendingcmds

运行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
	}
}
相关推荐
龙仔7253 天前
SQL Server 批量多库只读账号一键脚本(带逐行注释完整脚本 + 分段逐句详细解释)
服务器·数据库·sql·sqlserver·dba
xuefuhe8 天前
SQL Server查看系统存储过程及视图的定义
sqlserver
techdashen8 天前
Uber 如何完成超大规模 JUnit 迁移:从 JUnit 4 到 JUnit 5 的自动化工程实践
junit·sqlserver·自动化
xuefuhe10 天前
SQL Server Configuration Manager报Cannot connect to WMI provider错误
sqlserver
殳翰12 天前
spring对junit的支持
spring·junit·sqlserver
可触的未来,发芽的智生12 天前
发现-认知系统记忆架构工程启示录
数据库·人工智能·python·程序人生·sqlserver
ClouGence13 天前
SQL Server CDC 如何降低主库压力?Always On 备库读取实践
数据库·后端·sql·sqlserver
数据库小学妹1 个月前
SQL Server数据库同步工具怎么选?6款方案对比+信创迁移避坑清单
数据库·经验分享·sqlserver·dba
铁打的阿秀1 个月前
SQL server2025 Express安装及管理工具安装使用教程(Windows)
windows·sqlserver·express