Public/Functions/Licensing/Set-AzureAdUserLicenseServicePlan.ps1
# Module: TeamsFunctions # Function: VoiceConfig/Licensing # Author: David Eberhardt # Updated: 10-JAN-2021 # Status: PreLive function Set-AzureAdUserLicenseServicePlan { <# .SYNOPSIS Changes one or more Service Plans for Licenses assigned to an AzureAD Object .DESCRIPTION Enables or disables a ServicePlan from all assigned Licenses to an AzureAD Object Supports all Service Plans listed in Get-AzureAdLicenseServicePlan .PARAMETER Identity Required. UserPrincipalName of the Object to be manipulated .PARAMETER Enable Optional. Service Plans to be enabled (main function) Accepted Values can be retrieved with Get-AzureAdLicenseServicePlan (Column ServicePlanName) No action is taken for any Licenses not containing this Service Plan .PARAMETER Disable Optional. Service Plans to be disabled (alternative function) Accepted Values can be retrieved with Get-AzureAdLicenseServicePlan (Column ServicePlanName) No action is taken for any Licenses not containing this Service Plan .PARAMETER PassThru Optional. Displays User License Object after action. .EXAMPLE Set-AzureAdUserLicenseServicePlan -Identity Name@domain.com -Enable MCOEV Enables the Service Plan Phone System (MCOEV) on all Licenses assigned to Name@domain.com .EXAMPLE Set-AzureAdUserLicenseServicePlan -Identity Name@domain.com -Disable MCOEV,TEAMS1 Disables the Service Plans Phone System (MCOEV) and Teams (TEAMS1) on all Licenses assigned to Name@domain.com .EXAMPLE Set-AzureAdUserLicenseServicePlan -Identity Name@domain.com -Enable MCOEV,TEAMS1 -PassThru Enables the Service Plans Phone System (MCOEV) and Teams (TEAMS1) on all Licenses assigned to Name@domain.com Displays User License Object after application .NOTES Data in Get-AzureAdLicenseServicePlan as per Microsoft Docs Article: Published Service Plan IDs for Licensing https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/licensing-service-plan-reference#service-plans-that-cannot-be-assigned-at-the-same-time .COMPONENT Teams Migration and Enablement. License Assignment .ROLE Licensing .FUNCTIONALITY This script changes the AzureAD Object provided by enabling or disabling Service Plans on all Licenses assigned to an AzureAd Object .LINK https://github.com/DEberhardt/TeamsFunctions/tree/master/docs/ .LINK Get-TeamsTenantLicense .LINK Get-TeamsUserLicense .LINK Set-TeamsUserLicense .LINK Get-AzureAdLicense .LINK Get-AzureAdLicenseServicePlan #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] [Alias("Set-ServicePlan")] [OutputType([Void])] param( [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias("UPN", "UserPrincipalName", "Username")] [string[]]$Identity, [Parameter(HelpMessage = 'Service Plan(s) to be enabled on this Object')] [ValidateScript( { $ServicePlanNamesEnable = (Get-AzureAdLicenseServicePlan).ServicePlanName.Split('', [System.StringSplitOptions]::RemoveEmptyEntries) if ($_ -in $ServicePlanNamesEnable) { return $true } else { Write-Host "Parameter 'Enable' - Invalid Service Plan name. Supported Values can be found with Get-AzureAdLicenseServicePlan (Column ServicePlanName)" -ForegroundColor Red return $false } })] [string[]]$Enable, [Parameter(HelpMessage = 'Service Plan(s) to be disabled on this Object')] [ValidateScript( { $ServicePlanNamesDisable = (Get-AzureAdLicenseServicePlan).ServicePlanName.Split('', [System.StringSplitOptions]::RemoveEmptyEntries) if ($_ -in $ServicePlanNamesDisable) { return $true } else { Write-Host "Parameter 'Disable' - Invalid Service Plan name. Supported Values can be found with Get-AzureAdLicenseServicePlan (Column ServicePlanName)" -ForegroundColor Red return $false } })] [string[]]$Disable, [Parameter(Mandatory = $false)] [switch]$PassThru ) #param begin { Show-FunctionStatus -Level PreLive Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand)" # Asserting AzureAD Connection if (-not (Assert-AzureADConnection)) { 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')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { $DebugPreference = 'Continue' } # Validating input if ($PSBoundParameters.ContainsKey('Enable') -and $PSBoundParameters.ContainsKey('Disable')) { # Check if any are listed in both! Write-Verbose -Message "Validating input for Enable and Disable (identifying inconsistencies)" foreach ($Lic in $Enable) { if ($Lic -in $Disable) { Write-Error -Message "Invalid combination. '$Lic' cannot be enabled AND disabled" -Category LimitsExceeded -RecommendedAction "Please specify only once!" -ErrorAction Stop } } } # Querying licenses in the Tenant to compare SKUs try { Write-Verbose -Message "Querying Licenses from the Tenant" $TenantLicenses = Get-TeamsTenantLicense -Detailed -ErrorAction STOP } catch { Write-Warning $_ return } } #begin process { Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)" #region ForEach Identity foreach ($ID in $Identity) { #region Object Verification # Querying User try { $UserObject = Get-AzureADUser -ObjectId "$ID" -WarningAction SilentlyContinue -ErrorAction STOP Write-Verbose -Message "[PROCESS] $($UserObject.UserPrincipalName)" } catch { Write-Error -Message "User '$ID' - Account not valid" -Category ObjectNotFound -RecommendedAction "Verify UserPrincipalName" continue } # License Query from Object $ObjectAssignedLicenses = Get-AzureADUserLicenseDetail -ObjectId $UserObject.ObjectId -WarningAction SilentlyContinue if ($PSBoundParameters.ContainsKey('Debug')) { "Function: $($MyInvocation.MyCommand.Name): ServicePlanStatus for License:", ($ObjectAssignedLicenses.ServicePlans | Where-Object ProvisioningStatus -NE "Success" | Sort-Object ProvisioningStatus | Format-Table -AutoSize | Out-String).Trim() | Write-Debug } #endregion Write-Verbose -Message "Processing Service Plans" # iterating each License assigned to this Object foreach ($L in $ObjectAssignedLicenses) { # Determine License Name $LicenseName = ($TenantLicenses | Where-Object SkuPartNumber -EQ $L.SkuPartNumber).FriendlyName Write-Verbose -Message "User '$Identity' - License '$LicenseName'" # Verifying the License is still available in the Tenant $StandardLicense = Get-AzureADSubscribedSku | Where-Object { $_.SkuId -eq $L.SkuId } if ( -not $StandardLicense) { Write-Warning -Message "User '$Identity' - License '$LicenseName' - License not found in the Tenant!?" continue } # Creating a new License Object $License = New-AzureAdLicenseObject -AddSkuId $L.SkuId $DisabledPlans = $null $DisabledPlans = $L.ServicePlans | Where-Object ProvisioningStatus -EQ "Disabled" | Select-Object ServicePlanId -ExpandProperty ServicePlanId $($License.AddLicenses).DisabledPlans = $DisabledPlans if ($PSBoundParameters.ContainsKey('Debug')) { "Function: $($MyInvocation.MyCommand.Name): DisabledPlans:", ($License.AddLicenses.DisabledPlans | Format-List | Out-String).Trim() | Write-Debug } try { #region Enable - Iterating all provided Service Plans to enable [int]$EnabledPlans = 0 if ($PSBoundParameters.ContainsKey('Enable')) { foreach ($S in $Enable) { # Checking Service Plan is valid Write-Verbose -Message "User '$Identity' - License '$LicenseName' - Service Plan: '$S' (Enabling)" $ServicePlanToEnable = $null $ServicePlanToEnable = $StandardLicense | Where-Object ServicePlanName -EQ "$S" if ( -not $ServicePlanToEnable) { Write-Verbose -Message "User '$Identity' - License '$LicenseName' - Service Plan: '$S' not present" -Verbose continue } # Checking whether Service Plan is disabled if ( $ServicePlanToEnable.ServicePlanId -in $License.AddLicenses.DisabledPlans ) { if ( $($License.AddLicenses).DisabledPlans.Remove($ServicePlanToEnable.ServicePlanId) ) { $EnabledPlans++ if ($PSBoundParameters.ContainsKey('Debug')) { "Function: $($MyInvocation.MyCommand.Name): DisabledPlans:", ($($License.AddLicenses).DisabledPlans | Format-List | Out-String).Trim() | Write-Debug } } } else { Write-Information -MessageData "INFO: User '$Identity' - License '$LicenseName' - Service Plan '$S' is already enabled" -InformationAction Continue continue } } if ( -not $EnabledPlans ) { Write-Verbose -Message "User '$Identity' - License '$LicenseName' - No Service Plans to enable" #continue } } #endregion #region Disable - Iterating all provided Service Plans to disable [int]$DisabledPlans = 0 if ($PSBoundParameters.ContainsKey('Disable')) { foreach ($S in $Disable) { # Checking Service Plan is valid Write-Verbose -Message "User '$Identity' - License '$LicenseName' - Service Plan: '$S' (Disabling)" $ServicePlanToDisable = $null $ServicePlanToDisable = $StandardLicense | Where-Object ServicePlanName -EQ "$S" if ( -not $ServicePlanToDisable) { Write-Verbose -Message "User '$Identity' - License '$LicenseName' - Service Plan: '$S' not present" -Verbose continue } # Checking whether Service Plan is disabled if (-not ($ServicePlanToDisable.ServicePlanId -in $License.AddLicenses.DisabledPlans)) { $($License.AddLicenses).DisabledPlans += $ServicePlanToDisable.ServicePlanId $DisabledPlans++ if ($PSBoundParameters.ContainsKey('Debug')) { "Function: $($MyInvocation.MyCommand.Name): DisabledPlans:", ($($License.AddLicenses).DisabledPlans | Format-List | Out-String).Trim() | Write-Debug } } else { Write-Information -MessageData "INFO: User '$Identity' - License '$LicenseName' - Service Plan '$S' is already disabled" -InformationAction Continue continue } } } #endregion } catch { throw } # Catching non-assignments if ( $EnabledPlans -eq 0 -and $DisabledPlans -eq 0 ) { Write-Information -MessageData "INFO: User '$Identity' - License '$LicenseName' - No Service Plans to toggle. Validate License Assignments with Get-TeamsUserLicense or use PassThru" -InformationAction Continue continue } # Executing Assignment if ($PSBoundParameters.ContainsKey('Debug')) { "Function: $($MyInvocation.MyCommand.Name): LicensesToAssign:", ($License.AddLicenses | Format-List | Out-String).Trim() | Write-Debug "Function: $($MyInvocation.MyCommand.Name): DisabledPlans:", ($License.AddLicenses.DisabledPlans | Format-List | Out-String).Trim() | Write-Debug } if ($PSCmdlet.ShouldProcess("$ID", "Set-AzureADUserLicense")) { #Assign $LicenseObject to each User Write-Verbose -Message "'$ID' - Setting Licenses" Set-AzureADUserLicense -ObjectId $ID -AssignedLicenses $License Write-Verbose -Message "'$ID' - Setting Licenses: Done" } } #endregion # Output if ($PassThru) { Get-TeamsUserLicense -Identity $Identity } } } #process end { Write-Verbose -Message "[END ] $($MyInvocation.MyCommand)" } #end } #Set-AzureAdUserLicenseServicePlan |