Public/Licensing/Get-TeamsTenantLicense.ps1
# Module: TeamsFunctions # Function: Licensing # Author: David Eberhardt # Updated: 01-OCT-2020 # Status: Live function Get-TeamsTenantLicense { <# .SYNOPSIS Returns one or all Teams Tenant licenses from a Tenant .DESCRIPTION Returns an Object containing Teams related Licenses found in the Tenant Teams services can be provisioned through several different combinations of individual plans as well as add-on and grouped license SKUs. This command displays these license SKUs in a more friendly format with descriptive names, SkuPartNumber, active, consumed, remaining, and expiring licenses. .PARAMETER License Optional. Limits the Output to one license. Accepted Values can be retrieved with Get-AzureAdLicense (Column ParameterName) .PARAMETER ServicePlan Optional. Filters the Output to all Licenses where a specific ServicePlan is present. Accepted Values can be retrieved with Get-AzureAdLicenseServicePlan (Column ParameterName) .PARAMETER Detailed Displays all Parameters. By default, only Parameters relevant to determine License availability are shown. .PARAMETER DisplayAll Displays all Licenses, not only relevant Teams Licenses .EXAMPLE Get-TeamsTenantLicense Displays detailed information about all Teams related licenses found on the tenant. .EXAMPLE Get-TeamsTenantLicense -License PhoneSystem Displays detailed information about the PhoneSystem license found on the tenant. .EXAMPLE Get-TeamsTenantLicense -DisplayAll Displays values for all licenses, not only those found on the tenant. .EXAMPLE Get-TeamsTenantLicense -Detailed Displays detailed information of all licenses found on the tenant. .INPUTS System.String .OUTPUTS System.Object .NOTES Requires a connection to Azure Active Directory .COMPONENT Licensing .FUNCTIONALITY Returns a list of Licenses on the Tenant depending on input .LINK https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/Get-TeamsTenantLicense.md .LINK https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_Licensing.md .LINK https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/ #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'Required for performance. Removed with Disconnect-Me')] [CmdletBinding()] [OutputType([Object[]])] param( [Parameter(HelpMessage = 'Displays all Parameters')] [switch]$Detailed, [Parameter(HelpMessage = 'Displays all ServicePlans')] [switch]$DisplayAll, [Parameter(HelpMessage = 'License to be queried from the Tenant')] [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(HelpMessage = 'License to be queried from the Tenant')] [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 } } # 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' } #Loading License Array if (-not $global:TeamsFunctionsMSAzureAdLicenses) { $global:TeamsFunctionsMSAzureAdLicenses = Get-AzureAdLicense -WarningAction SilentlyContinue } $AllLicenses = $null $AllLicenses = $global:TeamsFunctionsMSAzureAdLicenses try { if ($PSBoundParameters.ContainsKey('License')) { $SkuPartNumber = ($AllLicenses | Where-Object ParameterName -EQ $License).SkuPartNumber $tenantSKUs = Get-AzureADSubscribedSku | Where-Object SkuPartNumber -EQ $SkuPartNumber -ErrorAction STOP if ($PSBoundParameters.ContainsKey('ServicePlan')) { Write-Warning -Message "Parameter ServicePlan is not processed when Parameter License is specified. Please remove one of them to enable filtering for either." } } else { if ($PSBoundParameters.ContainsKey('ServicePlan')) { $SkuPartNumber = ($AllLicenses | Where-Object { $_.ServicePlans.ServicePlanName -EQ $ServicePlan }).SkuPartNumber $tenantSKUs = Get-AzureADSubscribedSku | Where-Object SkuPartNumber -EQ $SkuPartNumber -ErrorAction STOP } else { $tenantSKUs = Get-AzureADSubscribedSku -ErrorAction STOP } } } catch { Write-Error $_ } } #begin process { Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)" [System.Collections.Generic.List[object]]$TenantLicenses = @() foreach ($tenantSKU in $tenantSKUs) { $Lic = $null $Lic = $AllLicenses | Where-Object SkuPartNumber -EQ "$($tenantSKU.SkuPartNumber)" if ($PSBoundParameters.ContainsKey('Debug')) { " Function: $($MyInvocation.MyCommand.Name) - SkuPartNumber: $($tenantSKU.SkuPartNumber)" | Write-Debug " Function: $($MyInvocation.MyCommand.Name) - tenantSKU", $tenantSKU | Write-Debug } # Current segmentation: Available = Enabled + Warning?; understand Suspended $LicUnitsAvailable = $tenantSKU.PrepaidUnits.Enabled + $tenantSKU.PrepaidUnits.Warning # + $tenantSKU.PrepaidUnits.Suspended # Omitted Suspended ones for now $LicUnitsConsumed = $tenantSKU.ConsumedUnits $LicUnitsRemaining = $LicUnitsAvailable - $LicUnitsConsumed $LicUnitsExpiring = $tenantSKU.PrepaidUnits.Warning if ($null -ne $Lic) { [void]$TenantLicenses.Add([TFTeamsTenantLicense]::new("$($Lic.ProductName)", "$($Lic.SkuPartNumber)", "$($Lic.LicenseType)", $Lic.ParameterName, $Lic.IncludesTeams, $Lic.IncludesPhoneSystem, $($Lic.SkuId), $Lic.ServicePlans, $LicUnitsAvailable, $LicUnitsConsumed, $LicUnitsRemaining, $LicUnitsExpiring)) } else { Write-Verbose "No published License (Get-AzureAdLicense) found for SkuId '$($tenantSKU.SkuId)', SkuPartNumber '$($tenantSKU.SkuPartNumber)'" if ($PSBoundParameters.ContainsKey('DisplayAll')) { [void]$TenantLicenses.Add([TFTeamsTenantLicense]::new('Unknown', "$($tenantSKU.SkuPartNumber)", 'Unknown', $null, $null, $null, $($tenantSKU.SkuId), 'Unknown', $LicUnitsAvailable, $LicUnitsConsumed, $LicUnitsRemaining, $LicUnitsExpiring)) } } } # Output if ($PSBoundParameters.ContainsKey('Detailed')) { Write-Output $TenantLicenses | Sort-Object ProductName } else { Write-Output $TenantLicenses | Sort-Object ProductName | Select-Object Available, Consumed, Remaining, ProductName, SkuPartNumber, LicenseType, ParameterName } } #process end { Write-Verbose -Message "[END ] $($MyInvocation.MyCommand)" } #end } #Get-TeamsTenantLicense |