functions/license/Get-PSEntraIDGroupLicense.ps1
|
function Get-PSEntraIDGroupLicense { <# .SYNOPSIS Get assigned licenses of a group with service plan status details. .DESCRIPTION Get assigned licenses of a group with resolved SKU names and service plan status details. .PARAMETER InputObject PSMicrosoftEntraID.Groups.Group object in tenant/directory. .PARAMETER Identity MailNickname, Mail or Id of the group attribute populated in tenant/directory. .PARAMETER EnableException This parameter disables user-friendly warnings and enables the throwing of exceptions. This is less user friendly, but allows catching exceptions in calling scripts. .EXAMPLE PS C:\> Get-PSEntraIDGroupLicense -Identity licensing-group Get assigned group licenses with enabled and disabled service plans. .NOTES Piping into Select-Object -First N logs a warning that is not a failure: WARNING: [<cmdlet>] Failed to: ... | The pipeline has been stopped The results are correct and complete. Select-Object stops the pipeline once it has what it asked for, and the next write throws PipelineStoppedException - normal termination, reported as an error only because the write happens inside a protected block. Materialise first if the warning is in the way: $items = @(<cmdlet> ...) $items | Select-Object -First 3 or filter server-side with -Filter instead of trimming client-side. Not silenced on purpose: the only fix that works is to collect the whole result before emitting any of it, which would cost streaming on every read. #> [OutputType('PSMicrosoftEntraID.Groups.AssignedLicenseDetail')] [CmdletBinding(DefaultParameterSetName = 'Identity')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'InputObject')] [PSMicrosoftEntraID.Groups.Group[]] $InputObject, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Identity')] [Alias('Id', 'GroupId', 'TeamId', 'MailNickName')] [ValidateGroupIdentity()] [string[]] $Identity, [Parameter()] [switch] $EnableException ) begin { [string] $service = Get-PSFConfigValue -FullName ('{0}.Settings.DefaultService' -f $script:ModuleName) Assert-EntraConnection -Service $service -Cmdlet $PSCmdlet [int] $commandRetryCount = Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryCount' -f $script:ModuleName) [System.TimeSpan] $commandRetryWait = New-TimeSpan -Seconds (Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryWaitInSeconds' -f $script:ModuleName)) [object[]] $subscribedLicenses = @(Get-PSEntraIDSubscribedLicense -EnableException:$EnableException) [object[]] $licenseIdentifiers = @(Get-PSEntraIDLicenseIdentifier -EnableException:$EnableException) [hashtable] $subscribedSkuById = @{} foreach ($subscribedLicense in $subscribedLicenses) { [string] $subscribedSkuId = $subscribedLicense.SkuId if (-not [string]::IsNullOrWhiteSpace($subscribedSkuId)) { $subscribedSkuById[$subscribedSkuId.ToLowerInvariant()] = $subscribedLicense } } [hashtable] $licenseIdentifiersBySkuId = @{} foreach ($licenseIdentifier in $licenseIdentifiers) { [string] $identifierSkuId = $licenseIdentifier.SkuId if (-not [string]::IsNullOrWhiteSpace($identifierSkuId)) { $licenseIdentifiersBySkuId[$identifierSkuId.ToLowerInvariant()] = $licenseIdentifier } } function ConvertTo-GroupAssignedLicenseDetail { param ( [Parameter(Mandatory = $true)] $GroupObject ) if ([object]::Equals($GroupObject.AssignedLicenses, $null) -or $GroupObject.AssignedLicenses.Count -eq 0) { return } foreach ($assignedLicense in @($GroupObject.AssignedLicenses)) { if ([object]::Equals($assignedLicense, $null)) { continue } [string] $skuId = $assignedLicense.SkuId [string] $skuKey = $null if (-not [string]::IsNullOrWhiteSpace($skuId)) { $skuKey = $skuId.ToLowerInvariant() } $subscribedLicense = $null if ($skuKey -and $subscribedSkuById.ContainsKey($skuKey)) { $subscribedLicense = $subscribedSkuById[$skuKey] } $licenseIdentifier = $null if ($skuKey -and $licenseIdentifiersBySkuId.ContainsKey($skuKey)) { $licenseIdentifier = $licenseIdentifiersBySkuId[$skuKey] } [hashtable] $servicePlanIdentifierById = @{} if ($licenseIdentifier -and -not [object]::Equals($licenseIdentifier.ServicePlans, $null)) { foreach ($servicePlanIdentifier in @($licenseIdentifier.ServicePlans)) { [string] $servicePlanIdentifierId = $servicePlanIdentifier.ServicePlanId if (-not [string]::IsNullOrWhiteSpace($servicePlanIdentifierId)) { $servicePlanIdentifierById[$servicePlanIdentifierId.ToLowerInvariant()] = $servicePlanIdentifier } } } [string[]] $disabledPlanIds = @() [hashtable] $disabledPlanLookup = @{} if (-not [object]::Equals($assignedLicense.DisabledPlans, $null)) { foreach ($disabledPlanId in @($assignedLicense.DisabledPlans)) { [string] $disabledPlanIdString = [string] $disabledPlanId if (-not [string]::IsNullOrWhiteSpace($disabledPlanIdString)) { $disabledPlanIds += $disabledPlanIdString $disabledPlanLookup[$disabledPlanIdString.ToLowerInvariant()] = $true } } } [System.Collections.Generic.List[object]] $servicePlanDetails = [System.Collections.Generic.List[object]]::new() [hashtable] $servicePlanSeen = @{} [object[]] $servicePlanSources = @() if ($subscribedLicense -and -not [object]::Equals($subscribedLicense.ServicePlans, $null)) { $servicePlanSources = @($subscribedLicense.ServicePlans) } elseif ($licenseIdentifier -and -not [object]::Equals($licenseIdentifier.ServicePlans, $null)) { $servicePlanSources = @($licenseIdentifier.ServicePlans) } foreach ($servicePlan in $servicePlanSources) { [string] $servicePlanId = [string] $servicePlan.ServicePlanId [string] $servicePlanKey = $null if (-not [string]::IsNullOrWhiteSpace($servicePlanId)) { $servicePlanKey = $servicePlanId.ToLowerInvariant() $servicePlanSeen[$servicePlanKey] = $true } $servicePlanIdentifier = $null if ($servicePlanKey -and $servicePlanIdentifierById.ContainsKey($servicePlanKey)) { $servicePlanIdentifier = $servicePlanIdentifierById[$servicePlanKey] } [bool] $isDisabled = $false if ($servicePlanKey -and $disabledPlanLookup.ContainsKey($servicePlanKey)) { $isDisabled = $true } $provisioningStatus = $null if ($servicePlan.PSObject.Properties['ProvisioningStatus']) { $provisioningStatus = $servicePlan.PSObject.Properties['ProvisioningStatus'].Value } $appliesTo = $null if ($servicePlan.PSObject.Properties['AppliesTo']) { $appliesTo = $servicePlan.PSObject.Properties['AppliesTo'].Value } [string] $servicePlanFriendlyName = $null if ($servicePlanIdentifier) { $servicePlanFriendlyName = $servicePlanIdentifier.ServicePlanFriendlyName } [string] $servicePlanStatus = 'Enabled' if ($isDisabled) { $servicePlanStatus = 'Disabled' } $servicePlanDetail = [PSCustomObject]@{ ServicePlanId = $servicePlanId ServicePlanName = $servicePlan.ServicePlanName ServicePlanFriendlyName = $servicePlanFriendlyName AppliesTo = $appliesTo ProvisioningStatus = $provisioningStatus Status = $servicePlanStatus IsDisabled = $isDisabled } $servicePlanDetail.PSObject.TypeNames.Insert(0, 'PSMicrosoftEntraID.Groups.AssignedLicenseServicePlanDetail') [void]$servicePlanDetails.Add($servicePlanDetail) } foreach ($disabledPlanId in $disabledPlanIds) { [string] $disabledPlanKey = $disabledPlanId.ToLowerInvariant() if ($servicePlanSeen.ContainsKey($disabledPlanKey)) { continue } $servicePlanIdentifier = $null if ($servicePlanIdentifierById.ContainsKey($disabledPlanKey)) { $servicePlanIdentifier = $servicePlanIdentifierById[$disabledPlanKey] } [string] $disabledServicePlanName = $null if ($servicePlanIdentifier) { $disabledServicePlanName = $servicePlanIdentifier.ServicePlanName } [string] $disabledServicePlanFriendlyName = $null if ($servicePlanIdentifier) { $disabledServicePlanFriendlyName = $servicePlanIdentifier.ServicePlanFriendlyName } $servicePlanDetail = [PSCustomObject]@{ ServicePlanId = $disabledPlanId ServicePlanName = $disabledServicePlanName ServicePlanFriendlyName = $disabledServicePlanFriendlyName AppliesTo = $null ProvisioningStatus = $null Status = 'Disabled' IsDisabled = $true } $servicePlanDetail.PSObject.TypeNames.Insert(0, 'PSMicrosoftEntraID.Groups.AssignedLicenseServicePlanDetail') [void]$servicePlanDetails.Add($servicePlanDetail) } [object[]] $servicePlanDetailArray = @($servicePlanDetails) [string] $skuPartNumber = $null if ($subscribedLicense) { $skuPartNumber = $subscribedLicense.SkuPartNumber } elseif ($licenseIdentifier) { $skuPartNumber = $licenseIdentifier.SkuPartNumber } [string] $skuFriendlyName = $null if ($licenseIdentifier) { $skuFriendlyName = $licenseIdentifier.SkuFriendlyName } $licenseDetail = [PSCustomObject]@{ GroupId = $GroupObject.Id GroupDisplayName = $GroupObject.DisplayName GroupMail = $GroupObject.Mail GroupMailNickname = $GroupObject.MailNickname SkuId = $skuId SkuPartNumber = $skuPartNumber SkuFriendlyName = $skuFriendlyName DisabledPlanIds = $disabledPlanIds DisabledPlanCount = @($servicePlanDetailArray | Where-Object -Property IsDisabled -EQ -Value $true).Count EnabledPlanCount = @($servicePlanDetailArray | Where-Object -Property IsDisabled -EQ -Value $false).Count TotalPlanCount = $servicePlanDetailArray.Count ServicePlans = $servicePlanDetailArray } $licenseDetail.PSObject.TypeNames.Insert(0, 'PSMicrosoftEntraID.Groups.AssignedLicenseDetail') $licenseDetail } } } process { switch ($PSCmdlet.ParameterSetName) { 'InputObject' { foreach ($itemInputObject in $InputObject) { $groupObject = $itemInputObject if ((-not $itemInputObject.PSObject.Properties['AssignedLicenses'] -or [object]::Equals($itemInputObject.AssignedLicenses, $null)) -and -not [string]::IsNullOrWhiteSpace($itemInputObject.Id)) { $groupObject = Get-PSEntraIDGroup -Identity $itemInputObject.Id -EnableException:$EnableException } if ([object]::Equals($groupObject, $null)) { continue } [string] $groupTarget = if (-not [string]::IsNullOrWhiteSpace($groupObject.DisplayName)) { $groupObject.DisplayName } else { $groupObject.Id } $result = Invoke-PSFProtectedCommand -ActionString 'Group.License.List' -ActionStringValues $groupTarget -Target (Get-PSFLocalizedString -Module $script:ModuleName -Name Identity.Platform) -ScriptBlock { ConvertTo-GroupAssignedLicenseDetail -GroupObject $groupObject } -EnableException:$EnableException -PSCmdlet $PSCmdlet -Continue -RetryCount $commandRetryCount -RetryWait $commandRetryWait -WhatIf:$false if (Test-PSFFunctionInterrupt) { return } $result } } 'Identity' { foreach ($group in $Identity) { $groupObject = Get-PSEntraIDGroup -Identity $group -EnableException:$EnableException if ([object]::Equals($groupObject, $null)) { if ($EnableException.IsPresent) { Invoke-TerminatingException -Cmdlet $PSCmdlet -Message ((Get-PSFLocalizedString -Module $script:ModuleName -Name Group.Get.Failed) -f $group) } continue } [string] $groupTarget = if (-not [string]::IsNullOrWhiteSpace($groupObject.DisplayName)) { $groupObject.DisplayName } else { $groupObject.Id } $result = Invoke-PSFProtectedCommand -ActionString 'Group.License.List' -ActionStringValues $groupTarget -Target (Get-PSFLocalizedString -Module $script:ModuleName -Name Identity.Platform) -ScriptBlock { ConvertTo-GroupAssignedLicenseDetail -GroupObject $groupObject } -EnableException:$EnableException -PSCmdlet $PSCmdlet -Continue -RetryCount $commandRetryCount -RetryWait $commandRetryWait -WhatIf:$false if (Test-PSFFunctionInterrupt) { return } $result } } } } end {} } |