Functions/Public/Alerts.ps1

# Alert configuration functions

Function Get-NectarAlertConfig {
    <#
        .SYNOPSIS
        Returns a list of Nectar DXP alert configurations
         
        .DESCRIPTION
        Returns a list of Nectar DXP alert configurations
 
        .PARAMETER AlertType
        The type of alert to return data on. Choose from 'NectarScore-Users', 'NectarScore-Locations', or 'PoorCalls'
 
        .PARAMETER TenantName
        The name of the Nectar DXP tenant. Used in multi-tenant configurations.
                 
        .PARAMETER ResultSize
        The number of results to return. Defaults to 10000.
         
        .EXAMPLE
        Get-NectarAlertConfig
        Returns the first 10000 alert configurations
         
        .EXAMPLE
        Get-NectarAlertConfig -ResultSize 100
        Returns the first 100 alert configurations
 
        .NOTES
        Version 1.0
    #>

    
    [Alias("gna")]    
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [Alias("ClientNotificationType")]
        [ValidateSet('NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION','NECTAR_SCORE_ALERT_BY_USER','REALTIME_NECTAR_SCORE_ALERT_BY_USER','ROOMS_AND_DEVICES_ALERT', IgnoreCase=$True)]
        [string]$AlertType,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$TenantName,
        [Parameter(Mandatory=$False)]
        [ValidateRange(1,100000)]
        [int]$ResultSize=10000
    )
    
    Begin {
        Connect-NectarCloud
    }        
    Process {
        Try {
            # Use globally set tenant name, if one was set and not explicitly included in the command
            If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { 
                $TenantName = $Global:NectarTenantName 
            } ElseIf ($TenantName) {
                If ($TenantName -NotIn $Global:NectarTenantList) {
                    $TList = $Global:NectarTenantList -join ', '
                    Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)"
                }
            }

            $Params = @{
                'tenant'                    = $TenantName
                'orderByField'                 = 'name'
                'orderDirection'             = 'asc'
                'pageSize'                    = $ResultSize
            }
            
            Switch ($AlertType) {
                {$_ -In 'NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION'} {
                    $URI = "https://$Global:NectarCloud/aapi/client/notification/poor-calls/configurations"
                    $Params.Add('clientNotificationType','NECTAR_SCORE_ALERT_BY_LOCATION,REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION')
                }
                {$_ -In 'NECTAR_SCORE_ALERT_BY_USER','NECTAR_SCORE_ALERT_BY_USER'} {
                    $URI = "https://$Global:NectarCloud/aapi/client/notification/uhs/configurations"
                    $Params.Add('types','NECTAR_SCORE_ALERT_BY_USER,REALTIME_NECTAR_SCORE_ALERT_BY_USER')
                }
                {$_ -In 'ROOMS_AND_DEVICES_ALERT'} {
                    $URI = "https://$Global:NectarCloud/aapi/client/alert/configuration"
                    $Params.Add('clientNotificationTypes','ROOMS_AND_DEVICES_ALERT')
                }
            }

            Write-Verbose $URI

            If (!$NectarError) {
                $JSON = Invoke-RestMethod -Method GET -URI $URI -Headers $Global:NectarAuthHeader -Body $Params
                If ($TenantName) { $JSON.elements | Add-Member -Name 'TenantName' -Value $TenantName -MemberType NoteProperty } # Add the tenant name to the output which helps pipelining
                $JSON.elements
            }
        }
        Catch {
            Write-Error "Unable to retrieve alert information. $($_.Exception.Message)"
            If ($PSCmdlet.MyInvocation.BoundParameters["ErrorAction"] -ne "SilentlyContinue") { Get-JSONErrorStream -JSONResponse $_ }        
        }
    }
}


Function Set-NectarAlertConfig {
    <#
        .SYNOPSIS
        Updates an existing Nectar alert configuration
 
        .DESCRIPTION
        Updates an existing Nectar alert configuration
         
        .PARAMETER Name
        The name of the alert to update
 
        .PARAMETER ID
        The ID of the alert to update
         
        .PARAMETER TimePeriod
        The time period to show session data from. Select from 'LAST_HOUR','LAST_DAY'
         
        .PARAMETER SessionQualities
        Show sessions that match a given quality rating. Case sensitive. Choose one or more from:
        'GOOD','POOR_0_25','PARTIALLY_GOOD_25_50','PARTIALLY_GOOD_50_75','PARTIALLY_GOOD_75_100','UNAVAILABLE','UNKNOWN'
         
        .PARAMETER NectarScore
        Show sessions that match the given range of NectarScores. Use format aa-xx or aa.bb-xx.yy, where aa is less than xx, and xx is less than 100. Eg. 70-90 or 95.00-95.59
         
        .PARAMETER TenantName
        The name of the Nectar DXP tenant. Used in multi-tenant configurations.
         
        .PARAMETER PageSize
        The size of the page used to return data. Defaults to 1000
         
        .PARAMETER ResultSize
        The total number of results to return. Defaults to 1000. Maximum result size is 9,999,999 results
         
        .EXAMPLE
        Get-NectarSession -TimePeriod LAST_HOUR -Platforms TEAMS -Modalities AUDIO -NectarScore 50-70
        Returns a list of all Teams audio sessions for the past hour where the NectarScore is between 50% and 70%
         
        .EXAMPLE
        (Get-NectarSession -SessionTypes CONFERENCE -TimePeriod CUSTOM -TimePeriodFrom '2021-05-06' -TimePeriodTo '2021-05-07').Count
        Returns a count of all conferences between May 6 and 7 (all times/dates UTC)
         
        .EXAMPLE
        Get-NectarSession -SessionTypes PEER2PEER,PEER2PEER_MULTIMEDIA -TimePeriod CUSTOM -TimePeriodFrom '2021-05-06 14:00' -TimePeriodTo '2021-05-06 15:00'
        Returns a list of all P2P calls between 14:00 and 15:00 UTC on May 6
 
        .EXAMPLE
        Get-NectarSession -TimePeriod LAST_WEEK -SessionTypes CONFERENCE | Select-Object confOrganizerOrSpace | Group-Object confOrganizerOrSpace | Select-Object Name, Count | Sort-Object Count -Descending
        Returns a list of conference organizers and a count of the total conferences organized by each, sorted by count.
         
        .NOTES
        Version 1.0
    #>

    
    [CmdletBinding(DefaultParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
    Param (
        [Parameter(Mandatory=$True)]
        [string]$Name,
        [Parameter(Mandatory=$False)]
        [int]$ID,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [Alias("ClientNotificationType")]
        [ValidateSet('NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION','NECTAR_SCORE_ALERT_BY_USER','REALTIME_NECTAR_SCORE_ALERT_BY_USER', IgnoreCase=$True)]
        [string]$AlertType,
        [Parameter(Mandatory=$False)]
        [int]$MinNSThreshold,
        [Parameter(Mandatory=$False)]
        [int]$MinTotalSessions,
        [Parameter(Mandatory=$False)]
        [string]$AlertHeader,
        [Parameter(Mandatory=$False)]
        [string]$AlertSubject,
        [Parameter(Mandatory=$False)]
        [bool]$SendEmail,
        [Parameter(Mandatory=$False)]
        [string[]]$EmailList,
        [Parameter(Mandatory=$False)]
        [bool]$EventAlert,
        [Parameter(Mandatory=$False)]
        [string]$EventActiveMessage,
        [Parameter(Mandatory=$False)]
        [string]$EventClearMessage,
        [Parameter(Mandatory=$False)]
        [datetime]$Time,
        [Parameter(Mandatory=$False)]
        [string]$TimeZone,
        [Parameter(Mandatory=$False)]
        [ValidateSet('LAST_HOUR','LAST_DAY','DYNAMIC', IgnoreCase=$True)]
        [string]$TimePeriod,
        [Parameter(Mandatory=$False)]
        [int]$DynamicPeriodMinutes,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$TenantName
    )
    
    Begin {
        Connect-NectarCloud
    }
    Process {
        # Use globally set tenant name, if one was set and not explicitly included in the command
        If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { 
                $TenantName = $Global:NectarTenantName 
            } ElseIf ($TenantName) {
                If ($TenantName -NotIn $Global:NectarTenantList) {
                    $TList = $Global:NectarTenantList -join ', '
                    Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)"
                }
            }

        $AlertConfig = Get-NectarAlertConfig -AlertType $AlertType -TenantName $TenantName | Where-Object {$_.Name -eq $Name}

        If (!$AlertConfig) {
            Throw "Could not find an event config with the name `'$Name`'. Please verify the alert config exists."
        }

        # Remove items that are not needed for the update
        $ExcludedItems = @('clientNotificationTypeId', 'cronExpression', 'createdDate', 'createdByPortalUserId', 'updatedDate', 'updatedByPortalUserId', 'triggeredCount', 'enabled')
        $IncludedItems = $AlertConfig.PSObject.Properties.Name | Where-Object { $_ -notin $ExcludedItems }
        $AlertConfig = $AlertConfig | Select-Object -Property $IncludedItems

        $State = @{
            'filters'        = $Filters
            'graphsFilter'    = @('TOTAL','AUDIO','VIDEO','APP_SHARING')
            'quality'        = @{'modality'             = @('audio','video')}
            'sessionList'    = @{'modality'             = 'ALL'
                                'orderByField'        = 'startDate'
                                'orderDirection'    = 'desc'
                                'pageNumber'        = 1
                                'pageSize'            = 10
                            }
        }

        $Params = @{
            'page'     = 'callDetails'
            'state'    = $State
        }

        $JSONParams = $Params | ConvertTo-Json -Depth 7

        $URI = "https://$Global:NectarCloud/dapi/link/share?tenant=$TenantName"
        Write-Verbose $URI

        $LinkID = Invoke-RestMethod_ErrorHandling -Method POST -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONParams -ContentType 'application/json; charset=utf-8'
        Write-Verbose "LinkID: $LinkID"
        Write-Verbose 'PSBoundParameters:'
        Write-Verbose $PSBoundParameters

        # Reduce down to all that needs to be imported back in
        $UpdatePayload = @{
            name                   = $AlertConfig.name
            thresholdFilter        = @{
                poorSessionPercentage = $AlertConfig.thresholdFilter.poorSessionPercentage
                minimumTotalSessions  = $AlertConfig.thresholdFilter.minimumTotalSessions
            }
            criticalAlertMessage   = $AlertConfig.criticalAlertMessage
            clearAlertMessage      = $AlertConfig.clearAlertMessage
            dataFilter             = @{
                timePeriod                 = $AlertConfig.dataFilter.timePeriod
                dynamicPeriodMinutes    = $AlertConfig.dataFilter.dynamicPeriodMinutes
                locations                  = $AlertConfig.dataFilter.locations
                platforms                  = $AlertConfig.dataFilter.platforms
                sessionTypes               = $AlertConfig.dataFilter.sessionTypes
                modalities                 = $AlertConfig.dataFilter.modalities
            }
            clientNotificationType = $AlertConfig.clientNotificationType
            recipients             = $AlertConfig.recipients
            hour                   = $AlertConfig.hour
            minute                 = $AlertConfig.minute
            linkId                 = $AlertConfig.linkId
            timeZone               = $AlertConfig.timeZone
            sendEmail              = $AlertConfig.sendEmail
            createEvent            = $AlertConfig.createEvent
        }

        # Create a property map of all possible values and their final resting location in the configmap
        $PropertyMap = @{
            Name                  = @{ Path = ''; Property = 'name' }
            ID                    = @{ Path = ''; Property = 'id' }
            AlertType             = @{ Path = ''; Property = 'clientNotificationType' }
            MinNSThreshold        = @{ Path = 'thresholdFilter'; Property = 'poorSessionPercentage' }
            MinTotalSessions      = @{ Path = 'thresholdFilter'; Property = 'minimumTotalSessions' }
            AlertHeader           = @{ Path = ''; Property = 'subject' }
            AlertSubject          = @{ Path = ''; Property = 'name' } # If different from $Name, change this
            SendEmail             = @{ Path = ''; Property = 'sendEmail' }
            EmailList             = @{ Path = ''; Property = 'recipients' }
            EventAlert            = @{ Path = ''; Property = 'createEvent' }
            EventActiveMessage    = @{ Path = ''; Property = 'criticalAlertMessage' }
            EventClearMessage     = @{ Path = ''; Property = 'clearAlertMessage' }
            Time                  = @{ Path = ''; Property = 'minute' } # Or split into hour/minute if needed
            TimeZone              = @{ Path = 'dataFilter'; Property = 'timeZone' }
            TimePeriod            = @{ Path = 'dataFilter'; Property = 'timePeriod' }
            DynamicPeriodMinutes  = @{ Path = 'dataFilter'; Property = 'dynamicPeriodMinutes' }
        }

        Switch ($AlertType) {
            {$_ -In 'NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION'} {
                $URI = "https://$Global:NectarCloud/aapi/client/notification/poor-calls/configuration/$($AlertConfig.id)?tenant=$TenantName"
            }
            {$_ -In 'NECTAR_SCORE_ALERT_BY_USER','NECTAR_SCORE_ALERT_BY_USER'} {
                $URI = "https://$Global:NectarCloud/aapi/client/notification/uhs/configuration/$($AlertConfig.id)?tenant=$TenantName"
            }
        }

        Write-Verbose $URI

        # Remove AlertType from PSBoundParameters. Otherwise, realtime alerts will not be updated properly
        $PSBoundParameters.Remove('AlertType')

        # Iterate through $PSBoundParameters and update the configmap
        ForEach ($Key in $PSBoundParameters.Keys) {
            If ($PropertyMap.ContainsKey($Key)) {
                $Map = $PropertyMap[$Key]
                $Path = $Map.Path
                $Prop = $Map.Property
                $Value = $PSBoundParameters[$Key]
        
                If ($Path -eq '') {
                    $UpdatePayload.$Prop = $Value
                } Else {
                    # Create the subobject if missing
                    If (-not $AC.$Path) {
                        $UpdatePayload.$Path = @{}
                    }
                    $UpdatePayload.$Path.$Prop = $Value
                }
            }
        }

        $JSONParams = $UpdatePayload | ConvertTo-Json -Depth 7
        Write-Verbose $JSONParams
        $JSON = Invoke-RestMethod_ErrorHandling -Method PUT -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONParams -ContentType 'application/json; charset=utf-8'
        Return $JSON
    }
}


Function New-NectarAlertConfig {
    <#
        .SYNOPSIS
        Creates a new Nectar alert configuration
 
        .DESCRIPTION
        Creates a new Nectar alert configuration
         
        .PARAMETER TimePeriod
        The time period to show session data from. Select from 'LAST_HOUR','LAST_DAY'
         
        .PARAMETER SessionQualities
        Show sessions that match a given quality rating. Case sensitive. Choose one or more from:
        'GOOD','POOR_0_25','PARTIALLY_GOOD_25_50','PARTIALLY_GOOD_50_75','PARTIALLY_GOOD_75_100','UNAVAILABLE','UNKNOWN'
         
        .PARAMETER NectarScore
        Show sessions that match the given range of NectarScores. Use format aa-xx or aa.bb-xx.yy, where aa is less than xx, and xx is less than 100. Eg. 70-90 or 95.00-95.59
         
        .PARAMETER DurationFrom
        The shortest call length (in seconds) to show session data.
         
        .PARAMETER DurationTo
        The longest call length (in seconds) to show session data.
         
        .PARAMETER Modalities
        Show sessions that match one or more modality types. Not case sensitive. Choose one or more from:
        'AUDIO','VIDEO','APP_SHARING','IM','UNKNOWN','TOTAL','VBSS','REMOTE_ASSISTANCE','APP_INVITE','FOCUS','UNKNOWN'
         
        .PARAMETER Protocols
        Show sessions that match one or more network protocol types. Case sensitive. Choose one or more from:
        'TCP','UDP','Unknown'
         
        .PARAMETER ResponseCodes
        Show sessions that match one or more SIP response codes. Accepts numbers from 200 to 699
         
        .PARAMETER SessionScenarios
        Show sessions that match one or more session scenarios. Not case sensitive. Choose one or more from:
        'External','Internal','Internal-External','External-Internal','Federated','Internal-Federated','External-Federated','Unknown'
         
        .PARAMETER SessionTypes
        Show sessions that match one or more session scenarios. Case sensitive. Choose one or more from:
        'Conference','Peer To Peer','Peer To Peer (Multimedia)','PSTN/External'
         
        .PARAMETER Codecs
        Show sessions where the selected codec was used by either caller or callee. Can query for multiple codecs. Case sensitive. Use Get-NectarCodecs for a list of valid codecs.
         
        .PARAMETER Devices
        Show sessions where the selected device was used by either caller or callee. Can query for multiple devices. Case sensitive. Use Get-NectarSupportedDevice for a list of valid devices.
 
        .PARAMETER DeviceVersions
        Show sessions where the selected device version was used by either caller or callee. Can query for multiple devices. Case sensitive. Use Get-NectarClientVersion for a list of valid client versions.
 
        .PARAMETER AgentVersions
        Show sessions where the selected agent version was used by either caller or callee. Can query for multiple agent. Case sensitive. Use Get-NectarAgentVersion for a list of valid agent versions.
 
        .PARAMETER IPAddresses
        Show sessions where the selected IP address was used by either caller or callee. Can query for multiple IPs.
         
        .PARAMETER Locations
        Show sessions where the selected location was used by either caller or callee. Can query for multiple locations.
         
        .PARAMETER ExtCities
        Show sessions where the caller or callee was located in the selected city (as detected via geolocating the user's external IP address). Can query for multiple cities.
         
        .PARAMETER ExtCountries
        Show sessions where the caller or callee was located in the selected country (as detected via geolocating the user's external IP address). Can query for multiple countries.
         
        .PARAMETER ExtISPs
        Show sessions where the caller or callee was located in the selected ISP (as detected via geolocating the user's external IP address). Can query for multiple ISPs.
 
        .PARAMETER ExtConnectionTypes
        Show sessions that match the caller or callee external connection type (as detected via geolocating the user's external IP address). Can query for multiple types.
     
        .PARAMETER NetworkTypes
        Show sessions where the selected network type was used by either caller or callee. Can query for multiple network types. Case sensitive. Choose one or more from:
        'CELLULAR','ENTERPRISE_WIFI','ENTERPRISE_WIRED','EXTERNAL_WIFI','EXTERNAL_WIRED','MOBILE','PPP','UNKNOWN','WIFI','WIRED'
 
        .PARAMETER Platforms
        Show sessions where the selected platform was used by either caller or callee. Can query for multiple platforms. Case sensitive. Choose one or more from:
        'SKYPE','CISCO','CISCO_CMS','CISCO_VKM','CISCO_WEBEX_CALLING','TEAMS','SKYPE_ONLINE','CISCO_CMS_VKM','AVAYA_AURA_CM','RIG','LYNC_VKM','SKYPE_FOR_BUSINESS_VKM','CISCO_UNITY','CISCO_EXPRESSWAY','AVAYA_MEDIA_GATEWAY','AVAYA_SESSION_MANAGER','AVAYA_VOICE_PORTAL','ZOOM','ENDPOINT_CLIENT','WEB_RTC_AIR_PHONE','WEB_RTC_AMAZON_CONNECT','WEB_RTC_CISCO_WEBEX','WEB_RTC_FIVE9','WEB_RTC_GENESYS_CLOUD','WEB_RTC_GENESYS_MCPE','WEB_RTC_NICE_CXONE','DIAGNOSTICS','GENESYS','JABRA','MISCELLANEOUS'
 
        .PARAMETER Servers
        Shows sessions where the selected server was used by either caller or callee. Can query for multiple servers.
        Must follow pattern of PLATFORM:SERVERNAME. Eg. 'CISCO:Server1', 'AVAYA_AURA_CM:Server2'
         
        .PARAMETER EndpointTypes
        Show sessions where one or more selected Avaya endpoint types have been used. Choose one or more from: 'medsvr','mgdsp','node','phone','unknown'
 
        .PARAMETER Users
        Show sessions where the selected user was either caller or callee. Can query for multiple users.
 
        .PARAMETER UserIDs
        Show sessions where the selected user ID was either caller or callee. Can query for multiple user IDs.
 
        .PARAMETER FromUserIDs
        Show sessions where the selected user ID was the caller. Can query for multiple user IDs.
         
        .PARAMETER ToUserIDs
        Show sessions where the selected user ID was the callee. Can query for multiple user IDs.
 
        .PARAMETER ConfOrganizers
        Show sessions hosted by a specified conference organizer. Can query for multiple organizers.
         
        .PARAMETER VPN
        Show sessions where the selected VPN was used by either caller or callee.
 
        .PARAMETER ParticipantsMinCount
        Show sessions where the number of participants is greater than or equal to the entered value
 
        .PARAMETER ParticipantsMaxCount
        Show sessions where the number of participants is less than or equal to the entered value
         
        .PARAMETER FeedbackRating
        Show sessions where users provided specific feedback ratings from BAD to EXCELLENT.
        Allowed values are BAD, POOR, FAIR, GOOD, EXCELLENT. Corresponds to ratings from 1 to 5 stars.
         
        .PARAMETER Insights
        Show sessions that match one or more given insights. Choose from NORMAL_SESSION, VOICE_MAIL, HIGH_JITTER, HIGH_PACKET_LOSS, HIGH_ROUNDTRIP_DELAY
         
        .PARAMETER OrderByField
        Sort the output by the selected field
         
        .PARAMETER OrderDirection
        Sort direction. Use with OrderByField. Not case sensitive. Choose from:
        ASC, DESC
 
        .PARAMETER TenantName
        The name of the Nectar DXP tenant. Used in multi-tenant configurations.
         
        .PARAMETER PageSize
        The size of the page used to return data. Defaults to 1000
         
        .PARAMETER ResultSize
        The total number of results to return. Defaults to 1000. Maximum result size is 9,999,999 results
         
        .EXAMPLE
        Get-NectarSession -TimePeriod LAST_HOUR -Platforms TEAMS -Modalities AUDIO -NectarScore 50-70
        Returns a list of all Teams audio sessions for the past hour where the NectarScore is between 50% and 70%
         
        .EXAMPLE
        (Get-NectarSession -SessionTypes CONFERENCE -TimePeriod CUSTOM -TimePeriodFrom '2021-05-06' -TimePeriodTo '2021-05-07').Count
        Returns a count of all conferences between May 6 and 7 (all times/dates UTC)
         
        .EXAMPLE
        Get-NectarSession -SessionTypes PEER2PEER,PEER2PEER_MULTIMEDIA -TimePeriod CUSTOM -TimePeriodFrom '2021-05-06 14:00' -TimePeriodTo '2021-05-06 15:00'
        Returns a list of all P2P calls between 14:00 and 15:00 UTC on May 6
 
        .EXAMPLE
        Get-NectarSession -TimePeriod LAST_WEEK -SessionTypes CONFERENCE | Select-Object confOrganizerOrSpace | Group-Object confOrganizerOrSpace | Select-Object Name, Count | Sort-Object Count -Descending
        Returns a list of conference organizers and a count of the total conferences organized by each, sorted by count.
         
        .NOTES
        Version 1.0
    #>

    
    [CmdletBinding(DefaultParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
    Param (
        [Parameter(Mandatory=$True)]
        [string]$Name,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [Alias("ClientNotificationType")]
        [ValidateSet('NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION','NECTAR_SCORE_ALERT_BY_USER','REALTIME_NECTAR_SCORE_ALERT_BY_USER', 'ROOMS_AND_DEVICES_ALERT', IgnoreCase=$True)]
        [string]$AlertType,
        [Parameter(Mandatory=$False)]
        [int]$MinNSThreshold = 60,
        [Parameter(Mandatory=$False)]
        [int]$MinTotalSessions = 10,
        [Parameter(Mandatory=$False)]
        [string]$AlertHeader = 'This automatically generated report shows the average Nectar Score for last time period.',
        [Parameter(Mandatory=$False)]
        [string]$AlertSubject = 'Nectar Score Alert',
        [Parameter(Mandatory=$False)]
        [bool]$SendEmail = $False,
        [Parameter(Mandatory=$False)]
        [string[]]$EmailList,
        [Parameter(Mandatory=$False)]
        [bool]$EventAlert = $False,
        [Parameter(Mandatory=$False)]
        [string]$EventActiveMessage = 'Nectar Score in $location_name is below $uhs_threshold %. User experience for this location is degraded.',
        [Parameter(Mandatory=$False)]
        [string]$EventClearMessage = 'Nectar Score in $location_name is above $uhs_threshold %. User experience for this location is restored to normal.',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [datetime]$Time = '12:05',
        [Parameter(Mandatory=$False)]
        [string]$TimeZone = "Etc/GMT$((Get-TimeZone).BaseUTCOffset.hours)",
        [Parameter(Mandatory=$False)]
        [ValidateSet('LAST_HOUR','LAST_DAY','DYNAMIC', IgnoreCase=$True)]
        [string]$TimePeriod = 'LAST_HOUR',
        [Parameter(Mandatory=$False)]
        [int]$DynamicPeriodMinutes = 30,
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$NectarScore = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('GOOD','POOR_0_25','PARTIALLY_GOOD_25_50','PARTIALLY_GOOD_50_75','PARTIALLY_GOOD_75_100','UNAVAILABLE','UNKNOWN','ALL', IgnoreCase=$True)]
        [string[]]$SessionQualities = 'ALL',    
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateRange(0,99999999)]
        [int]$DurationFrom = 1,
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateRange(0,99999999)]
        [int]$DurationTo,
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('AUDIO','VIDEO','APP_SHARING','IM','UNKNOWN','TOTAL','VBSS','REMOTE_ASSISTANCE','APP_INVITE','FOCUS', IgnoreCase=$True)]
        [string[]]$Modalities = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('TCP','UDP','Unknown','ALL', IgnoreCase=$False)]
        [string[]]$Protocols = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$ResponseCodes = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('INTERNAL','EXTERNAL','FEDERATED','INTERNAL_EXTERNAL','EXTERNAL_INTERNAL','FEDERATED_INTERNAL','INTERNAL_FEDERATED','FEDERATED_EXTERNAL','EXTERNAL_FEDERATED','UNKNOWN', IgnoreCase=$True)]
        [string[]]$SessionScenarios = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('CONFERENCE','CONFERENCE_SESSION','CONVERSATION_JOURNEY','PEER2PEER','PEER2PEER_MULTIMEDIA','PSTN', IgnoreCase=$False)]
        [string[]]$SessionTypes = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$Codecs = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$Devices = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$DeviceVersions = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$IPAddresses = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$Locations = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$ExtCities = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$ExtCountries = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$ExtISPs = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('Cable','Dialup','DSL','FTTx','ISDN','Unknown','Wireless','ALL', IgnoreCase=$False)]
        [string[]]$ExtConnectionTypes = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('CELLULAR','ENTERPRISE_WIFI','ENTERPRISE_WIRED','EXTERNAL_WIFI','EXTERNAL_WIRED','MOBILE','PPP','UNKNOWN','WIFI','WIRED', IgnoreCase=$False)]
        [string[]]$NetworkTypes = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('CISCO','CISCO_CMS','CISCO_VKM','CISCO_WEBEX_CALLING','TEAMS','CISCO_CMS_VKM','AVAYA_AURA_CM','ZOOM','ENDPOINT_CLIENT','WEB_RTC_AIR_PHONE','WEB_RTC_AMAZON_CONNECT','WEB_RTC_CISCO_WEBEX','WEB_RTC_FIVE9','WEB_RTC_GENESYS_CLOUD','WEB_RTC_GENESYS_MCPE','WEB_RTC_NICE_CXONE','DIAGNOSTICS','GENESYS','JABRA', IgnoreCase=$True)]
        [string[]]$Platforms = @(),
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$Servers,        
        [Parameter(Mandatory=$False)]
        [string[]]$Users = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [string[]]$ConfOrganizers,        
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('TRUE','FALSE','UNKNOWN','ALL', IgnoreCase=$True)]
        [string[]]$VPN = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateRange(0,99999)]
        [int]$ParticipantsMinCount,
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateRange(0,99999)]
        [int]$ParticipantsMaxCount,
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('BAD','POOR','FAIR','GOOD','EXCELLENT','ALL', IgnoreCase=$False)]
        [string[]]$FeedbackRating = 'ALL',
        [Parameter(Mandatory=$False, ParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
        [ValidateSet('NORMAL_SESSION','VOICE_MAIL','HIGH_JITTER','HIGH_PACKET_LOSS','HIGH_ROUNDTRIP_DELAY','AGENT', IgnoreCase=$False)]
        [string[]]$Insights = @('AGENT','NORMAL_SESSION','HIGH_JITTER','HIGH_PACKET_LOSS','HIGH_ROUNDTRIP_DELAY'),
        [switch]$ShowQualityDetails,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$TenantName
    )
    
    Begin {
        Connect-NectarCloud
    }
    Process {
        # Use globally set tenant name, if one was set and not explicitly included in the command
        If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { 
                $TenantName = $Global:NectarTenantName 
            } ElseIf ($TenantName) {
                If ($TenantName -NotIn $Global:NectarTenantList) {
                    $TList = $Global:NectarTenantList -join ', '
                    Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)"
                }
            }

        # Have to run this whole link share thing for some reason to return a link GUID to use in the actual creation of the rule
        $Filters = $PSBoundParameters
        $Filters.Add('excludeAvayaPpm', $True)
        $Filters.Add('platformServersOrDataCenters', @('All'))
        $Filters.Add('ratings', @('All'))
        $Filters.Add('sessionQualitySources', @('CDS','CDR_CDS'))

        $State = @{
            'filters'        = $Filters
            'graphsFilter'    = @('TOTAL','AUDIO','VIDEO','APP_SHARING')
            'quality'        = @{'modality'             = @('audio','video')}
            'sessionList'    = @{'modality'             = 'ALL'
                                'orderByField'        = 'startDate'
                                'orderDirection'    = 'desc'
                                'pageNumber'        = 1
                                'pageSize'            = 10
                            }
        }

        $Params = @{
            'page'     = 'callDetails'
            'state'    = $State
        }

        $JSONParams = $Params | ConvertTo-Json -Depth 7

        $URI = "https://$Global:NectarCloud/dapi/link/share?tenant=$TenantName"
        Write-Verbose $URI

        $LinkID = Invoke-RestMethod_ErrorHandling -Method POST -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONParams -ContentType 'application/json; charset=utf-8'
        Write-Verbose "LinkID: $LinkID"

        Switch ($AlertType) {
            { $_ -in @("NECTAR_SCORE_ALERT_BY_LOCATION", "REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION") } {
                $URI = "https://$Global:NectarCloud/aapi/client/notification/poor-calls/configuration/?tenant=$TenantName"
                Write-Verbose $URI

                If ($TimePeriod = 'DYNAMIC') { 
                    $FormattedAlertType = 'REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION' 
                }
                Else {
                    $FormattedAlertType = $AlertType
                }

                $DataFilter = @{
                    'dynamicPeriodMinutes'    = $DynamicPeriodMinutes
                    'locations'             = $Locations
                    'modalities'            = $Modalities
                    'platforms'                = $Platforms
                    'sessionTypes'            = $SessionTypes
                    'timePeriod'            = $TimePeriod
                }
        
                $AlertParams = @{
                    'clientNotificationType'    = $FormattedAlertType
                    'createEvent'                = $EventAlert
                    'dataFilter'                = $DataFilter
                    'hour'                        = $Time.hour
                    'linkId'                    = $LinkID
                    'minute'                    = $Time.minute
                    'name'                        = $Name
                    'recipients'                = $EmailList
                    'sendEmail'                    = $SendEmail
                    'subject'                    = $AlertSubject
                    'criticalAlertMessage'        = $EventActiveMessage
                    'clearAlertMessage'            = $EventClearMessage
                    'timeZone'                    = $TimeZone
                    'thresholdFilter'            = @{'poorSessionPercentage' = $MinNSThreshold
                                                    'minimumTotalSessions'    = $MinTotalSessions
                                                }
                }
            }
            'NECTAR_SCORE_ALERT' {
                If ($TimePeriod = 'DYNAMIC') { 
                    $FormattedAlertType = 'REALTIME_NECTAR_SCORE_ALERT_BY_USER' 
                }
                Else {
                    $FormattedAlertType = $AlertType
                }

                $URI = "https://$Global:NectarCloud/aapi/client/notification/uhs/configuration/?tenant=$TenantName"
                Write-Verbose $URI

                $AlertParams = @{
                    'activeDirectoryGroups'        = $ADGroupList
                    'checkEndpointClientUsers'    = $EPCUsers
                    'clientNotificationType'    = $FormattedAlertType
                    'createEvent'                = $CreateEvent
                    'emailBody'                    = $AlertHeader
                    'emailRecipients'            = $EmailList
                    'emailSubject'                = $AlertSubject
                    'includeAllUsers'            = $AllUsers
                    'monitoredUsersEmailBody'    = $MonitoredUserEmailBody
                    'monitoredUsersEmailSubject'= $MonitoredUserEmailSubject
                    'monitoredUsersSmsBody'        = $MonitoredUserSMSBody
                    'name'                        = $Name                    
                    'sendEmail'                    = $SendEmail
                    'sendMonitoredUsersEmail'    = $SendMonitoredUserEmail
                    'sendMonitoredUsersSms'        = $SendMonitoredUserSMS
                    'timeZone'                    = $TimeZone
                    'ushPercentage'                = $MinNSThreshold
                    'userIds'                    = $UserIDList
                    'userNames'                    = $UserNameList
                }
            }
            'ROOMS_AND_DEVICES_ALERT' {
                $URI = "https://$Global:NectarCloud/aapi/client/alert/configuration/?tenant=$TenantName"
                Write-Verbose $URI

                $AlertParams = @{
                    'name'                        = $Name    
                    'clientNotificationType'    = $AlertType
                    'createEvent'                = $EventAlert
                    'sendEmail'                    = $SendEmail
                    'enabled'                    = $True
                    'configJson' = @{
                        'timeZone'                = $TimeZone
                        'dataFilter'             = @{
                            'isDevices'         = $false
                            'isRooms'             = $true
                            'timePeriod'         = "DYNAMIC"
                            'filterRules'         = $null
                            'businessUnits'        = @()
                            'crvLocations'         = @()
                        }
                        'emailOptions' = @{
                            'subject'                     = $AlertSubject
                            'recipients'                 = $EmailList
                            'stateChangeAlertMessage'    = "Room `$room_name has changed its health state from `$old_health_state to `$new_health_state. This was caused by the device `$device_name changing from `$old_device_state to `$new_device_state, which was as a result of `$metric_name changing from `$old_metric_state to `$new_metric_state."
                        }
                        'scheduleOptions' = @{
                            'hour'         = $null
                            'minute'    = 5
                        }
                    }
                }
            }
        }

        Write-Verbose $URI

        $JSONParams = $AlertParams | ConvertTo-Json -Depth 7
        Write-Verbose $JSONParams

        $JSON = Invoke-RestMethod -Method POST -URI $URI -Headers $Global:NectarAuthHeader -Body $JSONParams -ContentType 'application/json; charset=utf-8'
        Return $JSON
    }
}


Function Remove-NectarAlertConfig {
    <#
        .SYNOPSIS
        Removes an existing Nectar alert configuration
 
        .DESCRIPTION
        Removes an existing Nectar alert configuration
 
        .PARAMETER AlertType
        The type of alert to delete
         
        .PARAMETER Name
        The name of the alert to remove
 
        .PARAMETER ID
        The ID of the alert to remove
         
        .PARAMETER TenantName
        The name of the Nectar DXP tenant. Used in multi-tenant configurations.
         
        .EXAMPLE
        Remove-NectarAlertConfig -Name 'Bad Alert'
        Removes the 'Bad Alert' from the system
         
        .NOTES
        Version 1.0
    #>

    
    [CmdletBinding(DefaultParameterSetName = 'NECTAR_SCORE_ALERT_BY_LOCATION')]
    Param (
        [Parameter(Mandatory=$True)]
        [string]$Name,
        [Parameter(Mandatory=$False)]
        [int]$ID,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [Alias("ClientNotificationType")]
        [ValidateSet('NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION','NECTAR_SCORE_ALERT_BY_USER','REALTIME_NECTAR_SCORE_ALERT_BY_USER', IgnoreCase=$True)]
        [string]$AlertType,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$TenantName
    )
    
    Begin {
        Connect-NectarCloud
    }
    Process {
        # Use globally set tenant name, if one was set and not explicitly included in the command
        If ($Global:NectarTenantName -And !$PSBoundParameters.ContainsKey('TenantName')) { 
                $TenantName = $Global:NectarTenantName 
            } ElseIf ($TenantName) {
                If ($TenantName -NotIn $Global:NectarTenantList) {
                    $TList = $Global:NectarTenantList -join ', '
                    Throw "Could not find a tenant with the name $TenantName on https://$Global:NectarCloud. Select one of $TList. $($_.Exception.Message)"
                }
            }

        $AlertConfig = Get-NectarAlertConfig -AlertType $AlertType -TenantName $TenantName | Where-Object {$_.Name -eq $Name}

        If (!$AlertConfig) {
            Throw "Could not find an event config with the name `'$Name`'. Please verify the alert config exists."
        }

        Switch ($AlertType) {
            {$_ -In 'NECTAR_SCORE_ALERT_BY_LOCATION','REALTIME_NECTAR_SCORE_ALERT_BY_LOCATION'} {
                $URI = "https://$Global:NectarCloud/aapi/client/notification/poor-calls/configuration/$($AlertConfig.id)?tenant=$TenantName"
            }
            {$_ -In 'NECTAR_SCORE_ALERT_BY_USER','NECTAR_SCORE_ALERT_BY_USER'} {
                $URI = "https://$Global:NectarCloud/aapi/client/notification/uhs/configuration/$($AlertConfig.id)?tenant=$TenantName"
            }
        }

        Write-Verbose $URI

        $NULL = Invoke-RestMethod_ErrorHandling -Method DELETE -URI $URI -Headers $Global:NectarAuthHeader
    }
}