Public/AutoAttendant/Get-TeamsAutoAttendant.ps1

# Module: TeamsFunctions
# Function: AutoAttendant
# Author: David Eberhardt
# Updated: 01-MAR-2022
# Status: Live

#IMPROVE Unknown what DialByNameResourceId is or does (GUID, denoting what object exactly? - how to test/query/translate?)
#TEST Output to be identical for Schedules,CallFlows,DefaultCallFlow, etc. like Get-CsAutoAttendant - only with -Detailed does it do this currently!

function Get-TeamsAutoAttendant {
  <#
  .SYNOPSIS
    Queries Auto Attendants and displays friendly Names (UPN or DisplayName)
  .DESCRIPTION
    Same functionality as Get-CsAutoAttendant, but display reveals friendly Names,
    like UserPrincipalName or DisplayName for the following connected Objects
    Operator and ApplicationInstances (Resource Accounts)
  .PARAMETER Name
    Required for ParameterSet Name. Finds all Auto Attendants with this name (unique results).
    If not provided, all Auto Attendants are queried, returning only the name
  .PARAMETER SearchString
    Required for ParameterSet Search. Searches all Auto Attendants for this string (multiple results possible).
  .PARAMETER Detailed
    Optional Switch. Displays nested Objects for all Parameters of the Auto Attendant
    By default, only Names of nested Objects are shown.
  .EXAMPLE
    Get-TeamsAutoAttendant
 
    Same result as Get-CsAutoAttendant
  .EXAMPLE
    Get-TeamsAutoAttendant -Name "My AutoAttendant"
 
    Returns an Object for every Auto Attendant found with the exact Name "My AutoAttendant"
  .EXAMPLE
    Get-TeamsAutoAttendant -Name "My AutoAttendant" -Detailed
 
    Returns an Object for every Auto Attendant found with the exact Name "My AutoAttendant"
    Detailed view will display all nested Objects indented as a tree
  .EXAMPLE
    Get-TeamsAutoAttendant -Name "My AutoAttendant" -SearchString "My AutoAttendant"
 
    Returns an Object for every Auto Attendant found with the exact Name "My AutoAttendant" and
    Returns an Object for every Auto Attendant matching the String "My AutoAttendant"
  .EXAMPLE
    Get-TeamsAutoAttendant -SearchString "My AutoAttendant"
 
    Returns an Object for every Auto Attendant matching the String "My AutoAttendant"
    Synonymous with Get-CsAutoAttendant -NameFilter "My AutoAttendant", but output shown differently.
  .INPUTS
    System.String
  .OUTPUTS
    System.Object
  .NOTES
    Without any parameters, Get-TeamsAutoAttendant will show names only.
    Operator and Resource Accounts, etc. are displayed with friendly name.
    Main difference to Get-CsAutoAttendant (apart from the friendly names) is how the Objects are shown.
    The connected Objects DefaultCallFlow, CallFlows, Schedules, CallHandlingAssociations and DirectoryLookups
    are all shown with Name only, but can be queried with .<ObjectName>
    This also works with Get-CsAutoAttendant, but with the help of "Display" Parameters.
  .COMPONENT
    TeamsAutoAttendant
  .FUNCTIONALITY
    Get-CsAutoAttendant with friendly names instead of GUID-strings for connected objects
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Get-TeamsAutoAttendant.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_TeamsAutoAttendant.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/
  #>


  [CmdletBinding(SupportsPaging, DefaultParameterSetName = 'Name')]
  [Alias('Get-TeamsAA')]
  [OutputType([System.Object[]])]
  param(
    [Parameter(ParameterSetName = 'Name', Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'Full Name of the Auto Attendant')]
    [AllowNull()]
    [Alias('Identity')]
    [string[]]$Name,

    [Parameter(ParameterSetName = 'Search', HelpMessage = 'Partial or full Name of the Auto Attendant to search')]
    [Alias('NameFilter')]
    [string]$SearchString,

    [Parameter()]
    [switch]$Detailed
  ) #param

  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 AzureAD Connection
    if ( -not $script:TFPSSA) { $script:TFPSSA = Assert-AzureADConnection; if ( -not $script:TFPSSA ) { break } }

    # 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' }

    #Initialising Counters
    $private:StepsID0, $private:StepsID1 = Get-WriteBetterProgressSteps -Code $($MyInvocation.MyCommand.Definition) -MaxId 1
    $private:ActivityID0 = $($MyInvocation.MyCommand.Name)
    [int] $private:CountID0 = [int] $private:CountID1 = 1

    #Initialising splatting Object
    $GetCsAutoAttendantParameters = @{
      WarningAction = 'SilentlyContinue'
      ErrorAction   = 'Continue'
    }
    if ( $PSBoundParameters.ContainsKey('First') ) { $GetCsAutoAttendantParameters.First = $PSCmdlet.PagingParameters.First }
    if ( $PSBoundParameters.ContainsKey('Skip') ) { $GetCsAutoAttendantParameters.Skip = $PSCmdlet.PagingParameters.Skip }
    if ( $PSBoundParameters.ContainsKey('IncludeTotalCount') ) { $GetCsAutoAttendantParameters.IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount }

    if ($PSBoundParameters.ContainsKey('Detailed')) {
      Write-Verbose -Message "Parameter 'Detailed' - This may take a bit of time..." -Verbose
    }

    $previousFEL = $global:FormatEnumerationLimit
    $global:FormatEnumerationLimit = 20

    #Worker Function
    function GetAutoAttendants {
      [CmdletBinding()]
      [OutputType([System.Object])]
      param(
        [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'Auto Attendant object')]
        [AllowNull()]
        [object]$AA,

        [Parameter()]
        [bool]$Detailed
      ) #param

      begin {

      }
      process {
        # Initialising counters for Progress bars
        [int] $private:CountID0 = 1
        $ActivityID0 = "'$($AA.Name)'"

        # Initialising Arrays
        [System.Collections.Generic.List[object]]$AIObjects = @()
        [System.Collections.Generic.List[object]]$AuthorizedUserObjects = @()

        $StatusID0 = 'Parsing'
        #region Finding Operator
        $CurrentOperationID0 = 'Operator'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        if ($null -eq $AA.Operator) {
          $AAOperator = $null
        }
        else {
          # Parsing Callable Entity
          try {
            $CallableEntity = Get-TeamsCallableEntity "$($AA.Operator.Id)" -WarningAction SilentlyContinue
            $Operator = $CallableEntity.Entity
          }
          catch {
            Write-Warning -Message "$ActivityID0 $StatusID0 $CurrentOperationID0`: Not enumerated: $($_.Exception.Message)"
          }
        }
        # Output: $Operator, $OperatorTranscription
        #endregion

        #region Application Instance UPNs
        $CurrentOperationID0 = 'Application Instances'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        foreach ($AI in $AA.ApplicationInstances) {
          $AIObject = $null
          $AIObject = Get-CsOnlineApplicationInstance -WarningAction SilentlyContinue | Where-Object { $_.ObjectId -eq $AI } | Select-Object UserPrincipalName, DisplayName, PhoneNumber
          if ($null -ne $AIObject) {
            [void]$AIObjects.Add($AIObject)
          }
        }
        # Output: $AIObjects.UserPrincipalName
        #endregion

        #region Inclusion & Exclusion Scope Groups
        $CurrentOperationID0 = 'Inclusion Scope Groups'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        if ($AA.DirectoryLookupScope.InclusionScope) {
          [System.Collections.Generic.List[object]]$InclusionScopeDistributionLists = @()
          foreach ($DL in $AA.DirectoryLookupScope.InclusionScope.GroupScope.GroupIds) {
            #$DLObject = Get-UniqueAzureADGroup "$DL" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
            $DLObject = $null
            $DLObject = Get-AzureADGroup -ObjectId "$DL" -WarningAction SilentlyContinue
            if ($DLObject) {
              [void]$InclusionScopeDistributionLists.Add($DLObject.DisplayName)
            }
          }
        }
        $CurrentOperationID0 = 'Exclusion Scope Groups'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        if ($AA.DirectoryLookupScope.ExclusionScope) {
          [System.Collections.Generic.List[object]]$ExclusionScopeDistributionLists = @()
          foreach ($DL in $AA.DirectoryLookupScope.ExclusionScope.GroupScope.GroupIds) {
            #$DLObject = Get-UniqueAzureADGroup "$DL" -WarningAction SilentlyContinue -ErrorAction SilentlyContinue
            $DLObject = $null
            $DLObject = Get-AzureADGroup -ObjectId "$DL" -WarningAction SilentlyContinue
            if ($DLObject) {
              [void]$ExclusionScopeDistributionLists.Add($DLObject.DisplayName)
            }
          }
        }
        # Output: $InclusionScopeDistributionLists, $ExclusionScopeDistributionLists
        #endregion

        #region Authorized Users
        $CurrentOperationID0 = 'Authorized Users'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        foreach ($User in $AA.AuthorizedUsers) {
          $UserObject = $null
          try {
            $UserObject = Get-AzureADUser -ObjectId "$($User.Guid)" -WarningAction SilentlyContinue -ErrorAction Stop | Select-Object UserPrincipalName, DisplayName, JobTitle, CompanyName, Country, UsageLocation, PreferredLanguage
            [void]$AuthorizedUserObjects.Add($UserObject)
          }
          catch {
            [string]$Message = $_ | Get-ErrorMessageFromErrorString
            Write-Warning -Message "'$($AA.Name)' - $Operation`: GetUser$($Message.Split(':')[1])"
          }

        }
        # Output: $AIObjects.UserPrincipalName
        #endregion

        #region Finding Artefacts
        $AfterHoursCHA = $AA.CallHandlingAssociations | Where-Object Type -EQ 'AfterHours'
        $AfterHoursScheduleId = $AfterHoursCHA.ScheduleId
        $AfterHoursCallFlowId = $AfterHoursCHA.CallFlowId

        $AfterHoursScheduleObject = $AA.Schedules | Where-Object Id -EQ $AfterHoursScheduleId
        $AfterHoursCallFlow = $AA.CallFlows | Where-Object Id -EQ $AfterHoursCallFlowId

        $HolidayCHA = $AA.CallHandlingAssociations | Where-Object Type -EQ 'Holiday'
        $HolidayScheduleId = $HolidayCHA.ScheduleId
        $HolidayCallFlowId = $HolidayCHA.CallFlowId

        $HolidayScheduleObject = $AA.Schedules | Where-Object Id -EQ $HolidayScheduleId
        $HolidayCallFlow = $AA.CallFlows | Where-Object Id -EQ $HolidayCallFlowId
        #endregion


        #region Creating Output Object
        # Building custom Object with Friendly Names
        $StatusID0 = 'Processing'
        $CurrentOperationID0 = 'Constructing Output Object'
        Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
        $AAObject = $null
        $AAObject = [PsCustomObject][ordered]@{
          PSTypeName                      = 'PowerShell.TeamsFunctsions.AutoAttendant'
          Identity                        = $AA.Identity
          Name                            = $AA.Name
          LanguageId                      = $AA.LanguageId
          TimeZoneId                      = $AA.TimeZoneId
          VoiceId                         = $AA.VoiceId
          VoiceResponseEnabled            = $AA.VoiceResponseEnabled
          OperatorName                    = $Operator
          OperatorType                    = $AA.Operator.Type
          Operator                        = $null
          DefaultCallFlowName             = $AA.DefaultCallFlow.Name
          AfterHoursCallFlow              = $AfterHoursCallFlow
          HolidayCallFlow                 = $HolidayCallFlow
          AfterHoursSchedule              = $AfterHoursScheduleObject
          HolidaySchedule                 = $HolidayScheduleObject
          DefaultCallFlow                 = $null
          CallFlows                       = $null
          Schedules                       = $null
          CallHandlingAssociations        = $null
          DialByNameResourceId            = $AA.DialByNameResourceId
          DirectoryLookupScope            = $AA.DirectoryLookupScope.Name
          InclusionScopeDistributionLists = $InclusionScopeDistributionLists
          ExclusionScopeDistributionLists = $ExclusionScopeDistributionLists
          AuthorizedUsers                 = $($AuthorizedUserObjects.UserPrincipalName -join ', ')
        }
        $AAObject.AfterHoursCallFlow | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
        $AAObject.HolidayCallFlow | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
        $AAObject.AfterHoursSchedule | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
        $AAObject.HolidaySchedule | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
        #endregion

        #region Extending Output Object with Switch Detailed
        if ( $Detailed ) {
          $StatusID0 = 'Switch Detailed (Nested Objects)'
          #region Operator
          $CurrentOperationID0 = 'Operator'
          Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
          if ($AA.Operator) {
            $AAOperator = @()
            $AAOperator = [PsCustomObject][ordered]@{
              PSTypeName            = 'PowerShell.TeamsFunctsions.AutoAttendant.Operator'
              'Entity'              = $Operator
              'Type'                = $AA.Operator.Type
              'EnableTranscription' = $AA.Operator.EnableTranscription
              'Id'                  = $AA.Operator.Id
            }
            Add-Member -Force -InputObject $AAOperator -MemberType ScriptMethod -Name ToString -Value {
              [System.Environment]::NewLine + (($this | Format-List * | Out-String) -replace '^\s+|\s+$')
            }
          }
          else {
            $AAOperator = $null
          }
          #endregion

          #region DefaultCallFlow
          $CurrentOperationID0 = 'DefaultCallFlow'
          Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
          Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: Prompts"
          #Write-Debug -Message "'$($AA.Name)' - $Operation - Prompts"
          if ( $AA.DefaultCallFlow.Menu.Prompts ) {
            $AADefaultCallFlowMenuPrompts = Merge-AutoAttendantArtefact -Type Prompt -Object $AA.DefaultCallFlow.Menu.Prompts
          }
          else {
            $AADefaultCallFlowMenuPrompts = ''
          }

          # Default Call Flow Menu Options
          Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: MenuOptions"
          #Write-Debug -Message "'$($AA.Name)' - $Operation - MenuOptions"
          if ( $AA.DefaultCallFlow.Menu.MenuOptions ) {
            [System.Collections.Generic.List[object]]$AADefaultCallFlowMenuOptions = @()
            foreach ( $MenuOption in $AA.DefaultCallFlow.Menu.MenuOptions ) {
              try {
                if ( $MenuOption.Prompt ) {
                  # Announcements: Processing Call Flow Prompts
                  Write-Debug -Message "'$($AA.Name)' - $Operation - MenuOptions - Prompt"
                  $MenuOptionPrompt = $null
                  $MenuOptionPrompt = Merge-AutoAttendantArtefact -Type Prompt -Object $MenuOption.Prompt
                  Write-Debug -Message "'$($AA.Name)' - $Operation - MenuOptions - MenuOptions"
                  $MenuOptionsObject = Merge-AutoAttendantArtefact -Type MenuOption -Object $MenuOption -Prompts $MenuOptionPrompt
                }
                else {
                  throw
                }
              }
              catch {
                Write-Debug -Message "'$($AA.Name)' - $Operation - MenuOptions - MenuOptions w/o prompt"
                $MenuOptionsObject = Merge-AutoAttendantArtefact -Type MenuOption -Object $MenuOption
              }
              $AADefaultCallFlowMenuOptions.Add($MenuOptionsObject)
            }
          }
          else {
            $AADefaultCallFlowMenuOptions = ''
          }

          # Default Call Flow Menu
          Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: Menu"
          #Write-Debug -Message "'$($AA.Name)' - $Operation - Menu"
          $AADefaultCallFlowMenu = Merge-AutoAttendantArtefact -Type Menu -Object $AA.DefaultCallFlow.Menu -Prompts $AADefaultCallFlowMenuPrompts -MenuOptions $AADefaultCallFlowMenuOptions

          # Default Call Flow Greetings
          if ($AA.DefaultCallFlow.Greetings) {
            $AADefaultCallFlowGreetings = Merge-AutoAttendantArtefact -Type Prompt -Object $AA.DefaultCallFlow.Greetings
          }
          else {
            $AADefaultCallFlowGreetings = ''
          }

          # Default Call Flow
          Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: Call Flow"
          #Write-Debug -Message "'$($AA.Name)' - $Operation - Call Flow"
          $AADefaultCallFlow = Merge-AutoAttendantArtefact -Type CallFlow -Object $AA.DefaultCallFlow -Prompts $AADefaultCallFlowGreetings -Menu $AADefaultCallFlowMenu
          #endregion

          #region CallFlows
          $CurrentOperationID0 = 'CallFlows'
          Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
          $AACallFlows = @()
          foreach ($Flow in $AA.CallFlows) {
            # Call Flow Prompts
            $AACallFlowMenuPrompts = $null
            Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - Prompts"
            #Write-Debug -Message "'$($AA.Name)' - $Operation - $($Flow.Name) - Prompts"
            if ($Flow.Menu.Prompts) {
              $AACallFlowMenuPrompts = Merge-AutoAttendantArtefact -Type Prompt -Object $Flow.Menu.Prompts
            }
            else {
              $AACallFlowMenuPrompts = ''
            }

            # Call Flow Menu Options
            $AACallFlowMenuOptions = $null
            Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - MenuOptions"
            #Write-Debug -Message "'$($AA.Name)' - $Operation - $($Flow.Name) - MenuOptions"
            if ($Flow.Menu.MenuOptions) {


              [System.Collections.Generic.List[object]]$AACallFlowMenuOptions = @()
              foreach ( $MenuOption in $Flow.Menu.MenuOptions ) {
                try {
                  if ( $MenuOption.Prompt ) {
                    # Announcements: Processing Call Flow Prompts
                    Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - MenuOptions - Prompt"
                    $MenuOptionPrompt = $null
                    $MenuOptionPrompt = Merge-AutoAttendantArtefact -Type Prompt -Object $MenuOption.Prompt
                    Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - MenuOptions - MenuOptions"
                    $MenuOptionsObject = Merge-AutoAttendantArtefact -Type MenuOption -Object $MenuOption -Prompts $MenuOptionPrompt
                  }
                  else {
                    throw
                  }
                }
                catch {
                  Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - MenuOptions - MenuOptions w/o prompt"
                  $MenuOptionsObject = Merge-AutoAttendantArtefact -Type MenuOption -Object $MenuOption
                }
                $AACallFlowMenuOptions.Add($MenuOptionsObject)
              }
            }
            else {
              $AACallFlowMenuOptions = ''
            }

            # Call Flow Menu
            Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - Menu"
            #Write-Debug -Message "'$($AA.Name)' - $Operation - $($Flow.Name) - Menu"
            $AACallFlowMenu = $null
            $AACallFlowMenu = Merge-AutoAttendantArtefact -Type Menu -Object $Flow.Menu -Prompts $AACallFlowMenuPrompts -MenuOptions $AACallFlowMenuOptions

            # Call Flow Greetings
            $AACallFlowGreetings = $null
            Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - Greetings"
            #Write-Debug -Message "'$($AA.Name)' - $Operation - $($Flow.Name) - Greetings"
            if ($Flow.Greetings) {
              $AACallFlowGreetings = Merge-AutoAttendantArtefact -Type Prompt -Object $Flow.Greetings
            }
            else {
              $AACallFlowGreetings = ''
            }

            # Call Flow
            Write-Debug -Message "$ActivityID0 - $StatusID0 - $CurrentOperationID0`: '$($Flow.Name)' - Call Flow"
            #Write-Debug -Message "'$($AA.Name)' - $Operation - $($Flow.Name) - Call Flow"
            $AACallFlows += Merge-AutoAttendantArtefact -Type CallFlow -Object $Flow -Prompts $AACallFlowGreetings -Menu $AACallFlowMenu
          }
          #endregion

          #region Schedules
          $CurrentOperationID0 = 'Schedules'
          Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
          $AASchedules = @()
          foreach ($Schedule in $AA.Schedules) {
            $AASchedule = Get-CsOnlineSchedule -Id $Schedule.Id
            $AASchedules += Merge-AutoAttendantArtefact -Type Schedule -Object $AASchedule
          }
          #endregion

          #region CallHandlingAssociations
          $CurrentOperationID0 = 'CallHandlingAssociations'
          Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
          $AACallHandlingAssociations = @()
          foreach ($item in $AA.CallHandlingAssociations) {
            # Determine Call Flow Name
            $AACallHandlingAssociationCallFlowName = ($AA.CallFlows | Where-Object Id -EQ $item.CallFlowId).Name
            # CallHandlingAssociations
            $AACallHandlingAssociations += Merge-AutoAttendantArtefact -Type CallHandlingAssociation -Object $item -CallFlowName $AACallHandlingAssociationCallFlowName
          }
          #endregion

          # Adding nested Objects
          $AAObject.Operator = $AAOperator
          $AAObject.DefaultCallFlow = $AADefaultCallFlow
          $AAObject.CallFlows = $AACallFlows
          $AAObject.Schedules = $AASchedules
          $AAObject.CallHandlingAssociations = $AACallHandlingAssociations

          <#
          # Adding nested Objects
          $AAObject | Add-Member -MemberType NoteProperty -Name Operator -Value $AAOperator
          $AAObject | Add-Member -MemberType NoteProperty -Name DefaultCallFlow -Value $AADefaultCallFlow
          $AAObject | Add-Member -MemberType NoteProperty -Name CallFlows -Value $AACallFlows
          $AAObject | Add-Member -MemberType NoteProperty -Name Schedules -Value $AASchedules
          $AAObject | Add-Member -MemberType NoteProperty -Name CallHandlingAssociations -Value $AACallHandlingAssociations
          #>

        }
        else {
          # Adding nested Objects
          $AAObject.Operator = $AA.Operator
          $AAObject.DefaultCallFlow = $AA.DefaultCallFlow
          $AAObject.CallFlows = $AA.CallFlows
          $AAObject.Schedules = $AA.Schedules
          $AAObject.CallHandlingAssociations = $AA.CallHandlingAssociations

          $AAObject.CallFlows | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
          $AAObject.Schedules | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force
          $AAObject.CallHandlingAssociations | Add-Member -MemberType ScriptMethod -Name ToString -Value { $this.Name } -Force

          <#
          # Adding Objects as is to allow drill-down
          $AAObject | Add-Member -MemberType NoteProperty -Name Operator -Value $AA.Operator
          $AAObject | Add-Member -MemberType NoteProperty -Name DefaultCallFlow -Value $AA.DefaultCallFlow
          $AAObject | Add-Member -MemberType NoteProperty -Name CallFlows -Value $AA.CallFlows
          $AAObject | Add-Member -MemberType NoteProperty -Name Schedules -Value $AA.Schedules
          $AAObject | Add-Member -MemberType NoteProperty -Name CallHandlingAssociations -Value $AA.CallHandlingAssociations
          #>

        }

        # Adding Resource Accounts
        $AAObject | Add-Member -MemberType NoteProperty -Name ApplicationInstances -Value $AIObjects.UserPrincipalName
        #endregion

        # Output
        Write-Progress -Id 1 -Activity $ActivityID0 -Completed
        Write-Progress -Id 0 -Activity $ActivityID0 -Completed
        Write-Output $AAObject
      }
      end {

      }
    }
  } #begin

  process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"
    [int] $private:CountID0 = [int] $private:CountID1 = 1
    $StatusID0 = 'Information Gathering'
    #region Data gathering
    $CurrentOperationID0 = 'Querying Auto Attendants'
    Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
    # Capturing no input
    if (-not $PSBoundParameters.ContainsKey('Name') -and -not $PSBoundParameters.ContainsKey('SearchString') ) {
      Write-Information 'INFO: No Parameters - Listing names only. To query individual items, please provide Parameter Name or SearchString'
      Get-CsAutoAttendant @GetCsAutoAttendantParameters | Select-Object Name
      return
    }
    else {
      $AutoAttendants = @()
      switch ($PSCmdlet.ParameterSetName) {
        'Name' {
          # Lookup
          Write-Verbose -Message "Parameter 'Name' - Querying unique result for each provided Name"
          foreach ($DN in $Name) {
            if ( $DN -match $script:TFMatchGuid ) {
              #Identity or ObjectId
              #NOTE MicrosoftTeams v2.3.1 - DO NOT use `-IncludeStatus` with Identity, it generates an error ParameterBindingException
              Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand.Name) - ID - '$DN'"
              $AAByName = Get-CsAutoAttendant -Identity "$DN" @GetCsAutoAttendantParameters
              $AutoAttendants += $AAByName
            }
            else {
              #Name
              Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand.Name) - Name - '$DN'"
              #$AAByName = Get-CsAutoAttendant -NameFilter "$DN" @GetCsAutoAttendantParameters
              $AAByName = Get-CsAutoAttendant -NameFilter "$DN" -IncludeStatus @GetCsAutoAttendantParameters
              $AAByName = $AAByName | Where-Object Name -EQ "$DN"
              $AutoAttendants += $AAByName
            }
          }
        }
        'Search' {
          # Search
          Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand.Name) - SearchString - '$SearchString'"
          #$AAbyName = Get-CsAutoAttendant -NameFilter "$SearchString" @GetCsAutoAttendantParameters
          $AAbyName = Get-CsAutoAttendant -NameFilter "$SearchString" -IncludeStatus @GetCsAutoAttendantParameters
          $AutoAttendants += $AAByName
        }
      }
    }
    #endregion

    # Parsing found Objects
    Write-Verbose -Message "[PROCESS] Processing found Auto Attendants: $($AutoAttendants.Count)"
    foreach ($AA in $AutoAttendants) {
      Write-Output (GetAutoAttendants -AA $AA -Detailed ($PSBoundParameters.ContainsKey('Detailed')) @args)
    }
  } #process

  end {
    Write-Verbose -Message "[END ] $($MyInvocation.MyCommand.Name)"
    if ($PSCmdlet.PagingParameters.IncludeTotalCount) {
      [double]$Accuracy = 1.0
      $PSCmdlet.PagingParameters.NewTotalCount($AutoAttendants, $Accuracy)
    }

    # Resetting EnumerationLimit
    $global:FormatEnumerationLimit = $previousFEL

  } #end
} #Get-TeamsAutoAttendant