Public/CommonAreaPhone/Remove-TeamsCommonAreaPhone.ps1

# Module: Orbit.Teams
# Function: VoiceConfig
# Author: David Eberhardt
# Updated: 01-JAN-2021
# Status: RC




function Remove-TeamsCommonAreaPhone {
  <#
  .SYNOPSIS
    Removes a Common Area Phone from Graph
  .DESCRIPTION
    This function allows you to remove Common Area Phones (GraphUser) from Graph
  .PARAMETER UserPrincipalName
    Required. Identifies the Object being changed
  .PARAMETER PassThru
    Optional. Displays UserPrincipalName of removed objects.
  .PARAMETER Force
    Optional. Suppresses Confirmation prompt to remove User.
  .EXAMPLE
    Remove-TeamsCommonAreaPhone -UserPrincipalName "Common Area Phone@TenantName.onmicrosoft.com"
 
    Removes a CommonAreaPhone
    Removes in order: Phone Number, License and Account
  .INPUTS
    System.String
  .OUTPUTS
    None
  .NOTES
    Execution requires User Admin Role in Azure AD
  .COMPONENT
    UserManagement
  .FUNCTIONALITY
    Removes a Common Area Phone in Graph
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/Orbit.Teams/Remove-TeamsCommonAreaPhone.md
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/about/about_VoiceConfiguration.md
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/about/about_UserManagement.md
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/
  #>


  [CmdletBinding(ConfirmImpact = 'High', SupportsShouldProcess)]
  [Alias('Remove-TeamsCAP')]
  [OutputType([System.Void])]
  param (
    [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, HelpMessage = 'UPN of the Object to create.')]
    [Alias('Identity', 'ObjectId')]
    [ValidateScript( {
        If ($script:OrbitRegexUPN.isMatch($_)) { $True } else {
          throw [System.Management.Automation.ValidationMetadataException] 'Value must be a valid UPN'
        } })]
    [string[]]$UserPrincipalName,

    [Parameter(Mandatory = $false)]
    [switch]$PassThru,

    [Parameter(Mandatory = $false)]
    [switch]$Force
  ) #param

  begin {
    Show-OrbitFunctionStatus -Level RC
    Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand)"

    # Asserting Graph Connection
    if ( -not (Test-GraphConnection) ) { throw 'Connection to Microsoft Graph not established. Please validate connection' }

    # Asserting MicrosoftTeams Connection
    if ( -not (Assert-MicrosoftTeamsConnection) ) { throw 'Connection to Microsoft Teams not established. Please validate connection' }

    # Setting Preference Variables according to Upstream settings
    if (-not $PSBoundParameters['Verbose']) { $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') }
    if (-not $PSBoundParameters['Confirm']) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') }
    if (-not $PSBoundParameters['WhatIf']) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') }
    $DebugPreference = if (-not $PSBoundParameters['Debug']) { $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { 'Continue' }
    $InformationPreference = if ( $PSBoundParameters['InformationAction']) { $PSCmdlet.SessionState.PSVariable.GetValue('InformationAction') } else { '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

    # Caveat - Access rights
    Write-Verbose -Message "This CmdLet requires the Office 365 Admin Role 'User Administrator' to execute Remove-GraphUser" -Verbose
    Write-Verbose -Message 'No verification of required admin roles is performed. Use Get-GraphAdminRole to determine roles for your account'

  } #begin

  process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"
    $StatusID0 = 'Processing Removal'
    #TEST Application of ID1
    [int] $private:StepsID0 = $private:StepsID0 * $(if ($UserPrincipalName.IsArray) { $UserPrincipalName.Count } else { 1 })
    foreach ($UPN in $UserPrincipalName) {
      $StatusID0 = $CurrentOperationID0 = ''
      Write-BetterProgress -Id 0 -Activity $ActivityID0 -Status $StatusID0 -CurrentOperation $CurrentOperationID0 -Step ($private:CountID0++) -Of $private:StepsID0
      $CountID1 = 1
      $ActivityID1 = "'$UPN'"
      $StatusID1 = 'Querying Object'
      #region Lookup of UserPrincipalName
      $CurrentOperationID1 = 'Querying CsOnlineUser'
      Write-BetterProgress -Id 1 -Activity $ActivityID1 -Status $StatusID1 -CurrentOperation $CurrentOperationID1 -Step ($private:CountID1++) -Of $private:StepsID1
      try {
        #Trying to query the Common Area Phone
        $Object = Get-MgUser -UserId "$UPN" -WarningAction SilentlyContinue -ErrorAction STOP
        $DisplayName = $Object.DisplayName
      }
      catch {
        # Catching anything
        Write-Warning -Message 'Object not found! Please provide a valid UserPrincipalName of an existing Common Area Phone'
        continue
      }
      #endregion

      #region Removing Voice Config
      $StatusID1 = "Processing Object '$DisplayName'"
      $CurrentOperationID1 = 'Removing Voice Configuration'
      Write-BetterProgress -Id 1 -Activity $ActivityID1 -Status $StatusID1 -CurrentOperation $CurrentOperationID1 -Step ($private:CountID1++) -Of $private:StepsID1
      try {
        Remove-TeamsUserVoiceConfig -UserPrincipalName $UPN -PassThru -ErrorAction Stop
      }
      catch {
        Write-Verbose "'$DisplayName' Object not licensed for Teams"
      }
      #endregion

      #region Licensing
      # Reading User Licenses
      $CurrentOperationID1 = 'Removing License Assignments'
      Write-BetterProgress -Id 1 -Activity $ActivityID1 -Status $StatusID1 -CurrentOperation $CurrentOperationID1 -Step ($private:CountID1++) -Of $private:StepsID1
      try {
        $UserLicenseSkuIDs = (Get-MgUserLicenseDetail -UserId "$UPN" -ErrorAction STOP -WarningAction SilentlyContinue).SkuId

        if ($null -eq $UserLicenseSkuIDs) {
          Write-Verbose -Message "'$DisplayName' No licenses assigned. OK"
        }
        else {
          #TEST This requires testing
          Write-Verbose -Message "'$DisplayName' Removing Removing licenses"
          Set-MgUserLicense -UserId $Object.ObjectId -RemoveLicenses $UserLicenseSkuIDs -ErrorAction STOP
          Write-Verbose -Message 'SUCCESS'
        }
      }
      catch {
        Write-Error -Message 'Removal of Licenses failed' -Category NotImplemented -Exception $_.Exception -RecommendedAction 'Try manually with Set-GraphUserLicense'
        return
      }
      #endregion

      #region Account Removal
      # Removing Graph User
      $CurrentOperationID1 = 'Removing Graph Object (GraphUser)'
      Write-BetterProgress -Id 1 -Activity $ActivityID1 -Status $StatusID1 -CurrentOperation $CurrentOperationID1 -Step ($private:CountID1++) -Of $private:StepsID1
      if ($Force -or $PSCmdlet.ShouldProcess("Common Area Phone with DisplayName: '$DisplayName'", 'Remove-MgUser')) {
        try {
          $null = (Remove-MgUser -UserId "$UPN" -ErrorAction STOP)
          Write-Verbose -Message 'SUCCESS - Object removed from Azure Active Directory'
        }
        catch {
          Write-Error -Message 'Removal failed' -Category NotImplemented -Exception $_.Exception -RecommendedAction 'Try manually with Remove-MgUser'
        }
      }
      else {
        Write-Verbose -Message 'SKIPPED - Object removed not confirmed Azure Active Directory'
      }
      #endregion

      # Output
      Write-Progress -Id 1 -Activity $ActivityID1 -Completed
      Write-Progress -Id 0 -Activity $ActivityID0 -Completed
      if ($PassThru) {
        Write-Output "GraphUser '$UserPrincipalName' removed"
      }
    }
  } #process

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

  } #end
} #Remove-TeamsCommonAreaPhone