Functions/Raise-SdtAlert.ps1

function Raise-SdtAlert
{
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()]
        [string]$Subject,
        [Parameter(Mandatory=$true)]
        [string]$Body,
        [Parameter(Mandatory=$false)]
        [string[]]$To = @($SdtDBAGroupMailId),
        [Parameter(Mandatory=$false, ParameterSetName="Email")]
        [string[]]$Attachments,
        [Parameter(Mandatory=$false, ParameterSetName="Email")]
        [Switch]$BodyAsHtml,
        [Parameter(Mandatory=$false, ParameterSetName="Email")]
        [string]$SmtpServer = $SdtSmtpServer,
        [Parameter(Mandatory=$false, ParameterSetName="Email")]
        [int]$Port = $SdtSmtpServerPort,
        [Parameter(Mandatory=$false, ParameterSetName="Email")][ValidateSet('Normal', 'High', 'Low')]
        $Priority = 'Normal',
        [Parameter(Mandatory=$false)][ValidateSet('Critical', 'High', 'Medium', 'Low')]
        $Severity = 'High',
        [Parameter(Mandatory=$false)][ValidateSet('Email', 'Slack', 'MSTeams')]
        $AlertType = 'Email',
        [Parameter(Mandatory=$false)]
        [int]$DelayMinutes = 15,
        [Switch]$ClearAlert
    )

    # Declare local variables
    $alert = $true
    if ($ClearAlert) {
        $alert = $false
    }

    $alertTime = Get-Date
    $alertTimeUTC = (Get-Date).ToUniversalTime()
    $alertTimeString = $alertTime.ToString('yyyy-MM-dd HH.mm.ss')
        
    $lastOccurredDateUTC = $alertTimeUTC
    $lastNotifiedDateUTC = $alertTimeUTC
    $newOccurredDateUTC = $alertTimeUTC
    $newNotifiedDateUTC = $alertTimeUTC
        
    Write-Debug "Inside Raise-SdtAlert.ps1"

    $currentAlert = @()
    $currentAlert += Invoke-DbaQuery -SqlInstance $SdtInventoryInstance -Database $SdtInventoryDatabase `
                -Query "select * from $SdtAlertTable a with (nolock) where alert_key = '$Subject' and state in ('active','suppressed')";
    
    
    # if alert is not active and history is found, then clear history
    if($ClearAlert -and $currentAlert.Count -gt 0)
    {
        Write-Verbose "Alert is inactive, but history is found."
        Write-Verbose "Clearing mail notification.."
        Send-MailMessage -From $SdtAlertEmailAddress -To $To -Subject $Subject -Body $Body -Priority $Priority `
                        -DeliveryNotificationOption OnSuccess, OnFailure `
                        -SmtpServer $SmtpServer -Port $Port -BodyAsHtml:$BodyAsHtml
        
        Write-Verbose "Marking cleared in alert table.."
        $alertUpdateSql = @"
set nocount on;
update a
set [state] = 'Cleared', last_occurred_date_utc = '$($newOccurredDateUTC.ToString('yyyy-MM-dd HH:mm:ss.fff'))'
from $SdtAlertTable a --with (nolock)
where alert_key = '$Subject' and state in ('active','suppressed')
"@

        Invoke-DbaQuery -SqlInstance $SdtInventoryInstance -Database $SdtInventoryDatabase -Query $alertUpdateSql -EnableException
    }

    # if alert is active but not found in history, then send mail notification and add entry into alert table
    if( (-not $ClearAlert) -and $currentAlert.Count -eq 0) 
    {
        $alert = $true
        Write-Verbose "No existing alert found for '$Subject'"
        Write-Verbose "Creating alert in alert table.."
        $alertUpdateSql = @"
set nocount on;
insert $SdtAlertTable (alert_key, email_to, severity)
select '$Subject', '$($To -join ',')', '$Severity';
"@

        Invoke-DbaQuery -SqlInstance $SdtInventoryInstance -Database $SdtInventoryDatabase -Query $alertUpdateSql -EnableException

        Write-Verbose "Sending mail notification.."
        if([String]::IsNullOrEmpty($Attachments)) {
            Send-MailMessage -From $SdtAlertEmailAddress -To $To -Subject $Subject -Body $Body -Priority $Priority -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SmtpServer -Port $Port -BodyAsHtml:$BodyAsHtml
        }
        else {
            Send-MailMessage -From $SdtAlertEmailAddress -To $To -Subject $Subject -Body $Body -Attachments $Attachments -Priority $Priority -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SmtpServer -Port $Port -BodyAsHtml:$BodyAsHtml
        }
    }

    # if alert is active, and present in history. Then update history
    if( (-not $ClearAlert) -and $currentAlert.Count -ne 0 ) 
    {
        Write-Verbose "Alert found for '$Subject' in alert table."
        $lastOccurredDateUTC = $currentAlert[0].last_occurred_date_utc
        $lastNotifiedDateUTC = $currentAlert[0].last_notified_date_utc        

        # if alert is out of $DelayMinutes
        if ($lastNotifiedDateUTC -le $alertTimeUTC.AddMinutes(-$DelayMinutes)) {
            $alert = $true
        }
        else { # no alert please
            $alert = $false
            $newNotifiedDateUTC = $lastNotifiedDateUTC
            "{0} {1,-10} {2}" -f "($((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')))","(INFO)","Raise-SdtAlert => Last alert was sent @ $((Get-SdtLocalTime $lastNotifiedDateUTC).ToString('yyyy-MM-dd HH.mm.ss'))" | Write-Output
            "{0} {1,-10} {2}" -f "($((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')))","(INFO)","Raise-SdtAlert => Last alert is within `$DelayMinutes ($DelayMinutes). So skipping current alert." | Write-Output
        }

        if( ($currentAlert[0].state -eq 'Suppressed') -and ($alertTimeUTC -ge $currentAlert[0].suppress_start_date_utc -and $alertTimeUTC -le $currentAlert[0].suppress_end_date_utc) ) {
            "{0} {1,-10} {2}" -f "($((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')))","(INFO)","Alert '$Subject' is in suppressed state." | Write-Output
            $alert = $false
            $newNotifiedDateUTC = $lastNotifiedDateUTC
        }

        Write-Verbose "Updating alert in alert table.."
        $alertUpdateSql = @"
set nocount on;
update a
set last_occurred_date_utc = '$($newOccurredDateUTC.ToString('yyyy-MM-dd HH:mm:ss.fff'))'
    $(if($alert){",last_notified_date_utc = '$($newNotifiedDateUTC.ToString('yyyy-MM-dd HH:mm:ss.fff'))', notification_counts += 1"})
from $SdtAlertTable a with (nolock)
where alert_key = '$Subject' and state in ('active','suppressed')
"@

        Invoke-DbaQuery -SqlInstance $SdtInventoryInstance -Database $SdtInventoryDatabase -Query $alertUpdateSql -EnableException

        if($alert)
        {
            Write-Verbose "Sending mail notification.."
            if([String]::IsNullOrEmpty($Attachments)) {
                Send-MailMessage -From $SdtAlertEmailAddress -To $To -Subject $Subject -Body $Body -Priority $Priority -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SmtpServer -Port $Port -BodyAsHtml:$BodyAsHtml
            }
            else {
                Send-MailMessage -From $SdtAlertEmailAddress -To $To -Subject $Subject -Body $Body -Attachments $Attachments -Priority $Priority -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SmtpServer -Port $Port -BodyAsHtml:$BodyAsHtml
            }
        }
    }
<#
.SYNOPSIS
    Send Alert on Email, Slack, or MS Teams.
.DESCRIPTION
    This function helps to send alert message with attachment using Mail, Slack or Microsoft Teams
.PARAMETER Subject
    Alert Subject. Would be used as Subject for Email.
.PARAMETER Body
    Text of alert body
.PARAMETER AlertKey
    String that uniquely identifies the Alert. Based on alert key, existing alert is found & cleared when required.
.PARAMETER To
    Receiver of alert. Could be comma separated list of email addresses, slack channel or team channel name.
.PARAMETER Attachments
    Comma separated list of documents to be sent with email as attachment.
.PARAMETER BodyAsHtml
    Switch when alert need to be send as html body.
.PARAMETER SmtpServer
    SMTP Server name
.PARAMETER Port
    SMTP Server port
.PARAMETER Priority
    Email priority. Possible values are Normal, High, Low. Default is Normal.
.PARAMETER AlertType
    Alert type. Possible values are Email, Slack, MSTeams. Default is Email.
.PARAMETER ClearAlert
    When this switch is used, alert matching by Alert Key would be cleared.
.EXAMPLE
    Raise-SdtAlert -To $SdtDBAMailId -Subject 'Raise-SdtAlert' -Body "Testing Email using SQLDBATools PowerShell module"
       
    Send a normal email alert
.EXAMPLE
    Raise-SdtAlert -To $SdtDBAMailId -Subject 'Raise-SdtAlert' -Body 'Testing Email using <span style="color:blue;">SQLDBATools</span> PowerShell module' -BodyAsHtml -Priority High
       
    Send a high priority email alert with html body
.LINK
    https://github.com/imajaydwivedi/SQLDBATools
#>

}