Public/VoiceConfig/Get-TeamsVoiceRoutingChain.ps1

# Module: TeamsFunctions
# Function: Tenant Voice Configuration
# Author: David Eberhardt
# Updated: 19-FEB-2022
# Status: Live




function Get-TeamsVoiceRoutingChain {
  <#
  .SYNOPSIS
    Queries an Online Voice Routing Policy and all associated Objects dependent on configuration
  .DESCRIPTION
    Returns a custom object detailing voice routing chain
  .PARAMETER Object
    CsOnlineVoiceRoutingPolicy Object. Identifying the Online Voice Routing Policy
    Required to identify the correct OVP and start the determination chain
  .PARAMETER Identity
    String. Name (Identity) of the Online Voice Routing Policy
    Required to identify the correct OVP and start the determination chain
  .PARAMETER Detailed
    Optional Switch. Displays nested Objects for all Elements of the Voice Routing Chain
    By default, only Names of nested Objects are shown.
  .EXAMPLE
    Get-TeamsVoiceRoutingChain -Identity "OVP-AMER-GSIP-MX"
 
    Queries the Online Voice Routing Policy OVP-AMER-GSIP-MX and determines the Chain.
    Determines Pstn Usages nested in this Policy and Voice Routes that reference this Pstn Usage.
  .EXAMPLE
    Get-TeamsVoiceRoutingChain -Identity "OVP-AMER-GSIP-MX" -Detailed
 
    Queries the Online Voice Routing Policy OVP-AMER-GSIP-MX and determines the Chain.
    Determines Pstn Usages nested in this Policy and Voice Routes that reference this Pstn Usage.
    Displays a tree object for the whole chain
  .EXAMPLE
    Get-TeamsVoiceRoutingChain -Identity $CsOnlineVoiceRoutingPolicy
 
    Queries the Online Voice Routing Policy Identified in the $CsOnlineVoiceRoutingPolicy Object and determines the Chain.
    Determines Pstn Usages nested in this Policy and Voice Routes that reference this Pstn Usage.
  .EXAMPLE
    $CsOnlineVoiceRoutingPolicy | Get-TeamsVoiceRoutingChain
 
    Queries the Online Voice Routing Policy Identified in the $CsOnlineVoiceRoutingPolicy Object and determines the Chain.
    Determines Pstn Usages nested in this Policy and Voice Routes that reference this Pstn Usage.
  .INPUTS
    System.String
    System.Object
  .OUTPUTS
    System.Object
  .NOTES
    Sister CmdLet to Find-TeamsUserVoiceRoute that focuses on determining a Route for a Call dependent on the dialled number
  .COMPONENT
    Tenant Voice Routing
  .FUNCTIONALITY
    Direct Routing
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Get-TeamsVoiceRoutingChain.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Find-TeamsUserVoiceRoute.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Find-TeamsEmergencyCallRoute.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_VoiceConfiguration.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/
  #>


  [CmdletBinding(DefaultParameterSetName = 'Name', ConfirmImpact = 'Low')]
  [Alias('Get-TeamsVRC')]
  [OutputType([PSCustomObject])]
  param(
    [Parameter(Mandatory, Position = 0, ParameterSetName = 'Object', ValueFromPipeline)]
    [Object[]]$Object,

    [Parameter(Mandatory, Position = 0, ParameterSetName = 'Name', ValueFromPipeline, HelpMessage = 'Name of the Online Voice Routing Policy')]
    [ValidateScript( {
        if ($_ -in $(&$global:TfAcSbVoiceRoutingPolicy)) { return $true } else {
          throw [System.Management.Automation.ValidationMetadataException] 'Value must be a valid Policy in the Tenant. Use Intellisense for options'
        } })]
    [ArgumentCompleter({ &$global:TfAcSbVoiceRoutingPolicy })]
    [string[]]$Identity,

    [switch]$Detailed
  )
  begin {
    Show-FunctionStatus -Level Live
    Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand.Name)"
    Write-Verbose -Message "Need help? Online: $global:TeamsFunctionsHelpURLBase$($MyInvocation.MyCommand.Name)`.md"
    # Asserting MicrosoftTeams Connection
    if ( -not (Assert-MicrosoftTeamsConnection) ) { break }

    # Setting Preference Variables according to Upstream settings
    if (-not $PSBoundParameters.ContainsKey('Verbose')) { $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') }
    if (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') }
    if (-not $PSBoundParameters.ContainsKey('WhatIf')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') }
    if (-not $PSBoundParameters.ContainsKey('Debug')) { $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { $DebugPreference = 'Continue' }
    if ( $PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSCmdlet.SessionState.PSVariable.GetValue('InformationAction') } else { $InformationPreference = 'Continue' }

    #region Defining Output Object
    class TFVoiceRoutingChain {
      [string]$OnlineVoiceRoutingPolicy
      $OnlinePstnUsageList
      $OnlineVoiceRouteList
      $OnlinePstnGatewayList
      [String]$NumberPattern
      hidden [System.Collections.Generic.List[object]]$VoiceRoutingChain

      TFVoiceRoutingChain(
        [string]$OnlineVoiceRoutingPolicy,
        $OnlinePstnUsageList,
        $OnlineVoiceRouteList,
        $OnlinePstnGatewayList,
        $NumberPattern
      ) {
        $this.OnlineVoiceRoutingPolicy = $OnlineVoiceRoutingPolicy
        $this.OnlinePstnUsageList = $OnlinePstnUsageList
        $this.OnlineVoiceRouteList = $OnlineVoiceRouteList
        $this.OnlinePstnGatewayList = $OnlinePstnGatewayList
        $this.NumberPattern = $NumberPattern
      }
    }
    #endregion

    # Preparing Splatting Object
    $Parameters = $null
    $Parameters = @{
      'Detailed' = ($Detailed)
    }

    #Worker functions
    Function GetVoiceRoutingChain {
      [CmdletBinding()]
      param(
        [Parameter(Mandatory)]
        [object]$Object,
        [switch]$Detailed
      )
      # Setting Preference Variables according to Upstream settings
      if (-not $PSBoundParameters.ContainsKey('Verbose')) { $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') }
      if (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') }
      if (-not $PSBoundParameters.ContainsKey('WhatIf')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') }
      if (-not $PSBoundParameters.ContainsKey('Debug')) { $DebugPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { $DebugPreference = 'Continue' }
      if ( $PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSCmdlet.SessionState.PSVariable.GetValue('InformationAction') } else { $InformationPreference = 'Continue' }

      Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"
      # Voice Routing
      $VoiceRoutingChain = [TFVoiceRoutingChain]::new($Object.Identity, $null, $null, $null, $null)
      if ($PSBoundParameters.ContainsKey('Debug') -or $DebugPreference -eq 'Continue') {
        "Function: $($MyInvocation.MyCommand.Name) - CsOnlineVoiceRoutingPolicy", ( $Object | Format-List | Out-String).Trim() | Write-Debug
      }

      Write-Verbose -Message "Online Voice Routing Policy '$($Object.Identity)'"
      $OPUs = $null
      $OPUs = $Object.OnlinePstnUsages
      if ($PSBoundParameters.ContainsKey('Debug') -or $DebugPreference -eq 'Continue') {
        "Function: $($MyInvocation.MyCommand.Name) - PSTN Usages: $($OPUs -join ', ')" | Write-Debug
      }

      if ($OPUs) {
        Write-Verbose -Message 'Online Pstn Usage'
        [System.Collections.Generic.List[object]]$OPUObjects = @()
        foreach ($OPU in $OPUs) {
          Write-Verbose -Message "Online Pstn Usage '$OPU'"
          $Routes += Get-CsOnlineVoiceRoute | Where-Object { $_.OnlinePstnUsages -contains $OPU } | Select-Object *, @{label = 'PSTNUsage'; Expression = { $OPU } }
          [System.Collections.Generic.List[object]]$VoiceRoutes = @()
          [System.Collections.Generic.List[object]]$OVRObjects = @()
          foreach ($Route in $Routes) {
            Write-Verbose -Message "Online Pstn Usage '$OPU' - Online Voice Route '$($Route.Name)'"
            if ( $VoiceRoutes -notcontains $Route ) {
              [void]$VoiceRoutes.Add($Route)
            }

            if ( $Detailed ) {
              [System.Collections.Generic.List[object]]$MGWObjects = @()
              foreach ($Gateway in $Route.OnlinePstnGatewayList) {
                Write-Verbose -Message "Online Pstn Usage '$OPU' - Online Voice Route '$($Route.Name)' - Gateway '$($Gateway.Identity)'"
                $CsOnlinePSTNGateway = Get-CsOnlinePSTNGateway $Gateway
                $MGWObject = Merge-VoiceRoutingChainArtefact -Type MGW -Object $CsOnlinePSTNGateway
                if ( $MGWObjects.Identity -notcontains $MGWObject.Identity ) {
                  [void]$MGWObjects.Add($MGWObject)
                }
              }
              $OVRObject = Merge-VoiceRoutingChainArtefact -Type OVR -Object $Route -MGWs $MGWObjects
              if ( $OVRObjects.Name -notcontains $OVRObject.Name ) {
                [void]$OVRObjects.Add($OVRObject)
              }
            }
          }
          if ($PSBoundParameters.ContainsKey('Debug') -or $DebugPreference -eq 'Continue') {
            "Function: $($MyInvocation.MyCommand.Name) - VoiceRoutes", ( $VoiceRoutes | Format-List | Out-String).Trim() | Write-Debug
          }

          $VoiceRoutingChain.OnlinePstnUsageList = $Object.OnlinePstnUsages
          if ( $VoiceRoutes ) {
            $VoiceRoutingChain.OnlineVoiceRouteList = $VoiceRoutes.Identity
            $VoiceRoutingChain.OnlinePstnGatewayList = $VoiceRoutes.OnlinePstnGatewayList
            $VoiceRoutingChain.NumberPattern = $VoiceRoutes.NumberPattern
          }
          else {
            Write-Warning -Message "OVP '$($Object.Identity)' - No Online Voice Routes have been found"
          }

          if ( $Detailed ) {
            Write-Verbose -Message 'Creating Voice Routing Chain Object'
            $OPUObject = Merge-VoiceRoutingChainArtefact -Type OPU -Object $OPU -OVRs $OVRObjects
            if ( $OPUObjects -notcontains $OPUObject ) {
              [void]$OPUObjects.Add($OPUObject)
            }
            #Adding Chained Object to Parent
            $VoiceRoutingChain.VoiceRoutingChain = $OPUObjects
          }
        }
      }
      else {
        Write-Warning -Message "OVP '$($Object.Identity)' - No Online PSTN Usages have been found"
      }

      if ( $Detailed ) {
        Write-Output $VoiceRoutingChain | Select-Object OnlineVoiceRoutingPolicy, OnlinePstnUsageList, OnlineVoiceRouteList, OnlinePstnGatewayList, NumberPattern, VoiceRoutingChain
      }
      else {
        Write-Output $VoiceRoutingChain
      }
    }
  }

  Process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"
    switch ($PSCmdlet.ParameterSetName) {
      'Name' {
        foreach ($Id in $Identity) {
          Write-Verbose -Message "[PROCESS] Processing '$Id'"
          try {
            if ($Id -match [regex]::Escape('*')) {
              $CsOnlineVoiceRoutingPolicy = Get-CsOnlineVoiceRoutingPolicy -Filter "*$Id*"-WarningAction SilentlyContinue -ErrorAction Stop
            }
            else {
              $CsOnlineVoiceRoutingPolicy = Get-CsOnlineVoiceRoutingPolicy -Identity "$Id"-WarningAction SilentlyContinue -ErrorAction Stop
            }
          }
          catch {
            Write-Error "CsOnlineVoiceRoutingPolicy '$Id' not found" -Category ObjectNotFound
            continue
          }
          foreach ($O in $CsOnlineVoiceRoutingPolicy) {
            Write-Verbose -Message "[PROCESS] Processing Found '$($O.Identity)'"
            GetVoiceRoutingChain -Object $O @Parameters @Args
          }
        }
      }
      'Object' {
        foreach ($O in $Object) {
          Write-Verbose -Message "[PROCESS] Processing provided CsOnlineVoiceRoutingPolicy Object for '$($O.Identity)'"
          GetVoiceRoutingChain -Object $O @Parameters @Args
        }
      }
    }
  }

  end {
    Write-Verbose -Message "[END ] $($MyInvocation.MyCommand)"
  }
} # Get-TeamsVoiceRoutingChain