Public/Support/Session/Assert-MicrosoftTeamsConnection.ps1

# Module: TeamsFunctions
# Function: Session
# Author: David Eberhardt
# Updated: 01-OCT-2020
# Status: Live

#TEST Returns TRUE (Object) if Connected but RBAC Roles have timed out - must capture PermissionDenied errors for GET-CmdLets
#BODGE Reconnect works but if Admin roles have timed out, no luck! Need to find logic to check AzureAd connection, then try enableing the roles and then reconnecting
#FIXME Rething whole function - what to do and when. Stick to it, don't try to do everyting
function Assert-MicrosoftTeamsConnection {
  <#
  .SYNOPSIS
    Asserts an established Connection to MicrosoftTeams
  .DESCRIPTION
    Tests a connection to MicrosoftTeams is established.
  .EXAMPLE
    Assert-MicrosoftTeamsConnection
 
    Will run Test-MicrosoftTeamsConnection and, if successful, stops.
    If unsuccessful, displays request to create a new session and stops.
  .INPUTS
    None
  .OUTPUTS
    System.Void - If called directly; On-Screen output only
    Boolean - If called by other CmdLets, On-Screen output for the first call only
  .NOTES
    None
  .COMPONENT
    TeamsSession
  .FUNCTIONALITY
    Verifies a Connection to AzureAd is established
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/master/docs/Assert-MicrosoftTeamsConnection.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/master/docs/about_TeamsSession.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/master/docs/
  #>


  [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Colourful feedback required to emphasise feedback for script executors')]
  [CmdletBinding()]
  [Alias('pol')]
  [OutputType([Boolean])]
  param() #param

  begin {
    #Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand)"
    Show-FunctionStatus -Level Live
    $Stack = Get-PSCallStack
    $Called = ($stack.length -ge 3)
    $Looped = ($Stack[1].Command -EQ $MyInvocation.MyCommand)

    if ( -not $global:TeamsFunctionsMSTeamsModule) { $global:TeamsFunctionsMSTeamsModule = Get-Module MicrosoftTeams }

    # Asserting AzureAD Connection
    if ( -not $script:TFPSSA) { $script:TFPSSA = Assert-AzureADConnection; if ( -not $script:TFPSSA ) { break } }

  } #begin

  process {
    #Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"

    if (Test-MicrosoftTeamsConnection) {
      if ( -not $Called ) { Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Connected!' }
      return $(if ($Called) { $true })
    }
    else {
      try {
        $null = Get-CsCallingLineIdentity -Identity Global -WarningAction SilentlyContinue -ErrorAction Stop
        if ( -not $Called ) { Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Reconnected!' }
        if ( $Looped ) { return $false } else { return ( Assert-MicrosoftTeamsConnection ) }
      }
      catch {
        if ( $_.Exception.Message -match 'You must call the Connect-MicrosoftTeams cmdlet before calling any other cmdlets' -or `
            $_.Exception.Message -match 'Session is not established' ) {
          if ( -not $Called ) { Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Session is not established' }
          if ( $script:TFPSSA) {
            $AzureAdConnection = Get-CurrentConnectionInfo
            Connect-MicrosoftTeams -AccountId $AzureAdConnection.Account -TenantId $AzureAdConnection.TenantId
            if ( $Looped ) { return $false } else { return ( Assert-MicrosoftTeamsConnection ) }
          }
          else {
            Write-Host '[ASSERT] MicrosoftTeams Session - No connection to Azure AD, create a new Session with Connect-Me!' -ForegroundColor Red
            return $(if ($Called) { $false })
          }
        }
        elseif ( $_.Exception.Message -match 'Broker response returned error: WAM Error Wam plugin' ) {
          Write-Host '[ASSERT] MicrosoftTeams Session - Inconsistent state (WAM Error - unrecoverable) - Please check your Admin Roles and create a new Session with Connect-Me!' -ForegroundColor Red
          Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Disconnecting from MicrosoftTeams' -Verbose
          $null = Disconnect-MicrosoftTeams
          return $(if ($Called) { $false })
        }
        elseif ( $_.Exception.Message -match 'Access Denied' ) {
          if ( -not $Called ) { Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Access Denied received' }
          try {
            if ( $script:TFPSSA) {
              $AzureAdConnection = Get-CurrentConnectionInfo
              Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Disconnecting from MicrosoftTeams' -Verbose
              $null = Disconnect-MicrosoftTeams
              Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Trying to activate AzureAd PIM Admin Roles - this takes 20+ seconds' -Verbose

              #VALIDATE Same code as Connect-Me - may want to generalise this into a private function input: Username, Output, roles or add it into Enable-MyAzureAdAdminRole
              $ActivatedRoles = Enable-MyAzureAdAdminRole -ErrorAction Stop
              $NrOfRoles = if ($ActivatedRoles.Count -gt 0) { $ActivatedRoles.Count } else { if ( $ActivatedRoles ) { 1 } else { 0 } }
              if ( $NrOfRoles -gt 0 ) {
                $Seconds = 15
                Write-Verbose -Message "[ASSERT] Enable-AzureAdAdminrole - $NrOfRoles Role(s) activated. Waiting for AzureAd to propagate ($Seconds`s)" -Verbose
                Start-Sleep -Seconds $Seconds
              }
              else {
                Write-Verbose 'Enable-AzureAdAdminrole - No roles have been activated - If Privileged Admin Groups are used, please activate via PIM: https://aka.ms/myroles ' -Verbose
              }

              Write-Verbose -Message '[ASSERT] MicrosoftTeams Session - Connecting to MicrosoftTeams' -Verbose
              $null = Connect-MicrosoftTeams
              if ( $stack.length -ge 5 ) { throw } else { return ( Assert-MicrosoftTeamsConnection ) }
            }
            else {
              Disconnect-Me
              Write-Host 'Error: No connection to AzureAd, please create a new Session with Connect-Me' -ForegroundColor Red
              return $(if ($Called) { $false })
            }
          }
          catch {
            Write-Host '[ASSERT] MicrosoftTeams Session - Connection Denied - Please check your Admin Roles and create a new Session with Connect-Me!' -ForegroundColor Red
            return $(if ($Called) { $false })
          }
        }
        else {
          Write-Host '[ASSERT] ERROR: MicrosoftTeams Session - No connection established or reconnect unsuccessful' -ForegroundColor Red
          return $(if ($Called) { $false })
        }
      }
    }
  } #process

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