Public/Support/Licensing/Test-TeamsUserLicense.ps1

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




function Test-TeamsUserLicense {
  <#
  .SYNOPSIS
    Tests a License or License Package assignment against an AzureAD-Object
  .DESCRIPTION
    Teams requires a specific License combination (License) for a User.
    Teams Direct Routing requires a specific License (ServicePlan), namely 'Phone System'
    to enable a User for Enterprise Voice
    This Script can be used to ascertain either.
  .PARAMETER UserPrincipalName
    Mandatory. The sign-in address, User Principal Name or Object Id of the Object.
  .PARAMETER ServicePlan
    Defined and descriptive Name of the Service Plan to test.
    Only ServicePlanNames pertaining to Teams are tested.
    Returns $TRUE only if the ServicePlanName was found and the ProvisioningStatus is "Success" at least once.
    ServicePlans can be part of multiple licenses, for Example MCOEV (PhoneSystem) is part of any E5 license.
    For Testing against a full License Package, please use Parameter License
  .PARAMETER License
    Defined and descriptive Name of the License Combination to test.
    This will test whether one more more individual Service Plans are present on the Identity
  .EXAMPLE
    Test-TeamsUserLicense -Identity User@domain.com -ServicePlan MCOEV
 
    Will Return $TRUE only if the ServicePlan is assigned and ProvisioningStatus is SUCCESS!
  .EXAMPLE
    Test-TeamsUserLicense -Identity User@domain.com -License Microsoft365E5
 
    Will Return $TRUE only if the license Package is assigned.
  .INPUTS
    System.String
  .OUTPUTS
    Boolean
  .NOTES
    This Script is indiscriminate against the User Type, all AzureAD User Objects can be tested.
    ServicePlans can be part of multiple licenses, for Example MCOEV (PhoneSystem) is part of any E5 license.
  .COMPONENT
    SupportingFunction
    Licensing
  .FUNCTIONALITY
    Returns a boolean value for License or Serviceplan for a specific user.
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Test-TeamsUserLicense.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_Supporting_Functions.md
  .LINK
    https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/
  #>


  [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'Required for performance. Removed with Disconnect-Me')]
  [CmdletBinding(DefaultParameterSetName = 'ServicePlan')]
  [OutputType([Boolean])]
  param(
    [Parameter(Mandatory, Position = 0, ValueFromPipeline, HelpMessage = 'This is the UserID (UPN)')]
    [Alias('ObjectId', 'Identity')]
    [ValidateScript( {
        If ($_ -match '@' -or $_ -match $script:TFMatchGuid) { $True } else {
          throw [System.Management.Automation.ValidationMetadataException] 'Value must be a valid UPN or ObjectId'
        } })]
    [string]$UserPrincipalName,

    [Parameter(Mandatory, ParameterSetName = 'License', HelpMessage = 'License to be tested')]
    [ValidateScript( {
        if ($_ -in $(&$global:TfAcSbAzureAdLicense)) { return $true } else {
          throw [System.Management.Automation.ValidationMetadataException] 'Value must be a valid License. Use Intellisense for options or Get-AzureAdLicense (ParameterName)'
        } })]
    [ArgumentCompleter({ &$global:TfAcSbAzureAdLicense })]
    [string]$License,

    [Parameter(Mandatory, ParameterSetName = 'ServicePlan', HelpMessage = 'AzureAd Service Plan')]
    [ValidateScript( {
        if ($_ -in $(&$global:TfAcSbAzureAdLicenseServicePlan)) { return $true } else {
          throw [System.Management.Automation.ValidationMetadataException] 'Value must be a valid ServicePlan. Use Intellisense for options or Get-AzureAdLicenseServicePlan (ServicePlanName)'
        } })]
    [ArgumentCompleter({ &$global:TfAcSbAzureAdLicenseServicePlan })]
    [string]$ServicePlan

  ) #param

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

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

    # Loading License Array
    if (-not $global:TeamsFunctionsMSAzureAdLicenses) {
      $global:TeamsFunctionsMSAzureAdLicenses = Get-AzureAdLicense -WarningAction SilentlyContinue
    }

    $AllLicenses = $null
    $AllLicenses = $global:TeamsFunctionsMSAzureAdLicenses


  } #begin

  process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"
    foreach ($ID in $UserPrincipalName) {
      # Query User
      try {
        $UserObject = Get-AzureADUser -ObjectId "$ID" -WarningAction SilentlyContinue
        $DisplayName = $UserObject.DisplayName
        $UserLicenseObject = Get-AzureADUserLicenseDetail -ObjectId $($UserObject.ObjectId) -WarningAction SilentlyContinue
      }
      catch {
        [string]$Message = $_ | Get-ErrorMessageFromErrorString
        Write-Warning -Message "User '$ID': GetUser$($Message.Split(':')[1])"
        return
      }

      # ParameterSetName ServicePlan VS License
      switch ($PsCmdlet.ParameterSetName) {
        'ServicePlan' {
          Write-Verbose -Message "'$DisplayName' Testing against '$ServicePlan'"
          if ($ServicePlan -in $UserLicenseObject.ServicePlans.ServicePlanName) {
            Write-Verbose -Message 'Service Plan found. Testing for ProvisioningStatus'
            #Checks if the Provisioning Status is also "Success"
            $ServicePlanStatus = ($UserLicenseObject.ServicePlans | Where-Object -Property ServicePlanName -EQ -Value $ServicePlan)
            Write-Verbose -Message "ServicePlan: $ServicePlanStatus"
            if ('Success' -in $ServicePlanStatus.ProvisioningStatus) {
              Write-Verbose -Message 'Service Plan found and provisioned successfully.'
              if ( $ServicePlanStatus.ProvisioningStatus.Count -gt 1 ) {
                Write-Warning -Message 'Multiple assignments found for PhoneSystem. Please verify License assignment!'
              }
              return $true
            }
            else {
              Write-Verbose -Message 'Service Plan found, but not provisioned successfully.'
              return $false
            }
          }
          else {
            Write-Verbose -Message 'Service Plan not found.'
            return $false
          }
        }
        'License' {
          Write-Verbose -Message "'$DisplayName' Testing against '$License'"
          $UserLicenseSKU = $UserLicenseObject.SkuPartNumber
          $Sku = ($AllLicenses | Where-Object ParameterName -EQ "$License").SkuPartNumber
          if ($Sku -in $UserLicenseSKU) {
            return $true
          }
          else {
            return $false
          }
        }
      }
    }
  } #process

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