Directly assigned or Inherited Office 365 Licenses ?

Hello, today I am sharing with you an interesting Office 365 script that I hope will help you. This script will tell you how licenses are assigned to a set of user in your Office 365 tenant : Direct or Inherited ?

My script consists of 2 parts, the first determines License Plans assigned to a user account, the second one dertermines the Licenses paths (Direct or Inherited).

function Get-LicensePlan {
    param (
        [Parameter(Mandatory=$true)]
        [String]$SkuId,
        [Parameter(mandatory=$true)]
        [String]$TenantName
    )

    Switch($SkuId){
                      "$($TenantName):AAD_PREMIUM" {return "AAD Premium P1"}
                   "$($TenantName):AX7_USER_TRIAL" {return "D_AX7.0 TRIAL"}
          "$($TenantName):DYN365_ENTERPRISE_P1_IW" {return "D365 ETR P1"}
              "$($TenantName):DYN365_RETAIL_TRIAL" {return "D365 CRM TRIAL"}
                              "$($TenantName):EMS" {return "EMS_E3"}
                       "$($TenantName):EMSPREMIUM" {return "EMS_E5"}
                     "$($TenantName):DESKLESSPACK" {return "F1"}
                     "$($TenantName):STANDARDPACK" {return "E1"}
                   "$($TenantName):ENTERPRISEPACK" {return "E3"}
                "$($TenantName):ENTERPRISEPREMIUM" {return "E5"}
                        "$($TenantName):FLOW_FREE" {return "FLOW FREE"}
                      "$($TenantName):INTUNE_A_VL" {return "INTUNE"}
                       "$($TenantName):MCOMEETADV" {return "SFB PSTN Conf"}
        "$($TenantName):MICROSOFT_BUSINESS_CENTER" {return "MBC"}
                     "$($TenantName):POWER_BI_PRO" {return "PBI PRO"}
                "$($TenantName):POWER_BI_STANDARD" {return "PBI STD"}
        "$($TenantName):POWERAPPS_INDIVIDUAL_USER" {return "PAPPS IND User"}
                  "$($TenantName):POWERAPPS_VIRAL" {return "PAPPS and LOGIC FLOW"}
                   "$($TenantName):PROJECTPREMIUM" {return "PJ Online"}
                           "$($TenantName):STREAM" {return "STREAM"}
                "$($TenantName):VISIOONLINE_PLAN1" {return "VISIO P1"}
              "$($TenantName):WACONEDRIVESTANDARD" {return "OD P1"}
                      "$($TenantName):WIN_DEF_ATP" {return "WDF ATP"}
                                           default {return $SkuId.Replace("$($TenantName):","")}
    }
}

With the function Get-LicensePlan, we know what licenses are assigned to a user based on the SkuId. The following second function Get-LAPATH (Get-LicenseAssingmentPaths) will tell us if the licenses are Direct assigned or Inherited from a group.

function Get-LAPATH{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]$UPN
    )

    Begin{
        Get-Date
        Write-Host "## Data processing stated at $(Get-date)" -ForegroundColor Yellow
        Write-Host ""
        $TenantName = ((Get-MsolAccountSku).AccountSkuId[0] -split(':'))[0]
    }

    Process{
        
        Write-Host ""
        Write-Host "Working on $UPN" -ForegroundColor Green
        $User = Get-MsolUser -UserPrincipalName $UPN

        #Getting assignment paths
        $LicensesTab = $null
        $LicensePlan = $null
        $LicTabCount = 0
        $LicensesTab = $User.Licenses | Select-Object AccountSkuId, GroupsAssigningLicense

        if($LicensesTab){

            Write-Host "License Enabled : True" -ForegroundColor Yellow

            $i = 0 #(Measure-Object -InputObject $LicensesTab).Count
            $LicTabCount = $LicensesTab.AccountSkuId.Count

            Do{

                #Getting License Plan
                $LicensePlan = Get-LicensePlan -SkuId $LicensesTab[$i].AccountSkuId -TenantName $TenantName

                #Getting License Paths
                [System.Collections.ArrayList]$LicensePath = @()

                if($LicensesTab[$i].GroupsAssigningLicense){

                    foreach ($Guid in $LicensesTab[$i].GroupsAssigningLicense.guid){

                        if($Guid -eq $User.ObjectId.Guid){
                            $LicensePath.Add("Direct") | Out-Null
                        }
                        else{
                            $LicensePath.Add((Get-MsolGroup -ObjectId $Guid).DisplayName) | Out-Null
                        }

                    }
                }
                else{
                    $LicensePath.Add("Direct") | Out-Null
                }

                Write-Host "$LicensePlan : $([String]::Join(",",$LicensePath.ToArray()))" -ForegroundColor Yellow
                $i++

            }
            While ($i -ne $LicTabCount)
        }
        else {
            Write-Host "License Enabled : false" -ForegroundColor Red
        }
    }

    End{
        Write-Host ""
        Write-Host "## Data Processing ended on $(Get-Date)" -ForegroundColor Yellow
    }

}

Now that everything is set, let’s talk about how to use this script to achieve your goal. Of course, for running this script, you need to have Microsoft Online Services PowerShell installed on your computer (PowerShell Module For Office 365) and a read access permissions on your Office 365 Admin portal to see users configuration,  ideally User Management Role. 

  • To see Office 365 license assginment paths for one user
"<UserPrincipalName>" | Get-LAPATH
Get-LAPATH_multiples_One

The user james.bond@acidalien.fr has 3 licenses plans assigned:

  1. FLOW FREE inherited from the license group GRP-FLOW-FREE
  2. FLOW FREE directly assigned
  3. DEVELOPERPACK directly assigned
  • To see Office 365 license assignment paths for several users 

From a Powershell table

"User1 upn" ,"User2 upn","..." | Get-LAPATH
Get-LAPATH_multiples_2

From a file containing the list of UserPrincipalName :

Get-LAPATH_multiples_File
Get-Content -Path <File path.txt> | Get-LAPATH
Get-LAPATH_multiples

Et voilà 🙂

12 thoughts on “Directly assigned or Inherited Office 365 Licenses ?

    1. Hello Doug,
      1/ If you have not installed the msolonline powershelle module, use this link : https://docs.microsoft.com/en-us/powershell/azure/active-directory/install-msonlinev1?view=azureadps-1.0

      2/ Open a powershell console, Run the cmdlet Connect-MsolService to connect msolonline sevice
      3/ Copy/pass the two scripts functions Get-LicensePlan and Get-LAPATH in order to upload the functions
      4/ Run the cmdlet in two ways :

      – using upns
      “” ,””,”…” | Get-LAPATH

      -using a txt file containing upns
      Get-Content -Path | Get-LAPATH

      Hope it’s helped

      Like

  1. Thanks for the quick reply. I have MSOnline module installed. When I execute it the I just get a command prompt.

    PS C:\scripts\LicensePath> Connect-MsolService
    PS C:\scripts\LicensePath> “testuser@mydomain.com” | Get-LAPath
    PS C:\scripts\LicensePath>

    I guess I don’t understand ‘3/ Copy/pass the two scripts functions Get-LicensePlan and Get-LAPATH in order to upload the functions’

    I have created 2 .ps1 scripts, Get-LicensePlan.ps1 and Get-LAPath.ps1 and saved them to my c:\scripts\LicensePath folder.
    I cd to that folder and execute the command. Should they be saved in another location?

    Sorry for the questions I am still learning PS and haven’t dealt with these types of scripts before.

    Like

    1. You don’t need to save the script in .ps1 file
      0/ connect-msolservice
      1/ copy the script : function Get-LicensePlan{…} and pass directly in your powershell console
      2/ copy the script : function Get-LAPATH{…} and pass it directly in your powershell console
      3/then run the cmdlet testuser@mydomain.com | Get-LAPath

      Like

  2. Thank you. I finally got it to work.
    I copied/pasted the code into my ps session and was able to run the cmdlet testuser@mydomain.com | Get-LAPath and it returned the results like in your screenshots. YAY!!!
    I also figured out how to save them as .psm1 files and import them and it worked that way too.
    Much appreciated!!! You totally rock!!!

    Like

    1. To export, use this version of the script:

      function Get-LicensePlan {
      param (
      [Parameter(Mandatory=$true)]
      [String]$SkuId,
      [Parameter(mandatory=$true)]
      [String]$TenantName
      )

      Switch($SkuId){
      “$($TenantName):AAD_PREMIUM” {return “AAD Premium P1”}
      “$($TenantName):AX7_USER_TRIAL” {return “D_AX7.0 TRIAL”}
      “$($TenantName):DYN365_ENTERPRISE_P1_IW” {return “D365 ETR P1”}
      “$($TenantName):DYN365_RETAIL_TRIAL” {return “D365 CRM TRIAL”}
      “$($TenantName):EMS” {return “EMS_E3”}
      “$($TenantName):EMSPREMIUM” {return “EMS_E5”}
      “$($TenantName):DESKLESSPACK” {return “F1”}
      “$($TenantName):STANDARDPACK” {return “E1”}
      “$($TenantName):ENTERPRISEPACK” {return “E3”}
      “$($TenantName):ENTERPRISEPREMIUM” {return “E5”}
      “$($TenantName):FLOW_FREE” {return “FLOW FREE”}
      “$($TenantName):INTUNE_A_VL” {return “INTUNE”}
      “$($TenantName):MCOMEETADV” {return “SFB PSTN Conf”}
      “$($TenantName):MICROSOFT_BUSINESS_CENTER” {return “MBC”}
      “$($TenantName):POWER_BI_PRO” {return “PBI PRO”}
      “$($TenantName):POWER_BI_STANDARD” {return “PBI STD”}
      “$($TenantName):POWERAPPS_INDIVIDUAL_USER” {return “PAPPS IND User”}
      “$($TenantName):POWERAPPS_VIRAL” {return “PAPPS and LOGIC FLOW”}
      “$($TenantName):PROJECTPREMIUM” {return “PJ Online”}
      “$($TenantName):STREAM” {return “STREAM”}
      “$($TenantName):VISIOONLINE_PLAN1” {return “VISIO P1”}
      “$($TenantName):WACONEDRIVESTANDARD” {return “OD P1”}
      “$($TenantName):WIN_DEF_ATP” {return “WDF ATP”}
      default {return $SkuId.Replace(“$($TenantName):”,””)}
      }
      }

      function Get-LAPATH{

      [CmdletBinding()]

      Param(
      [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
      [string]$UPN,
      [Parameter(Mandatory=$true)]
      [string]$ExportPath

      )

      Begin{
      Get-Date
      Write-Host “## Data processing stated at $(Get-date)” -ForegroundColor Blue
      Write-Host “”
      $TenantName = ((Get-MsolAccountSku)[0].AccountSkuId -split(‘:’))[0]
      }

      Process{

      Write-Host “”
      Write-Host “Working on $UPN” -ForegroundColor Green
      $User = Get-MsolUser -UserPrincipalName $UPN

      #Getting assignment paths
      $LicensesTab = $null
      $LicensePlan = $null
      $LicTabCount = 0
      $LicensesTab = $User.Licenses | Select-Object AccountSkuId, GroupsAssigningLicense

      if($LicensesTab){

      Write-Host “License Enabled : True” -ForegroundColor Yellow

      $i = 0 #(Measure-Object -InputObject $LicensesTab).Count
      $LicTabCount = $LicensesTab.AccountSkuId.Count

      Do{
      #Getting License Plan
      $LicensePlan = Get-LicensePlan -SkuId $LicensesTab[$i].AccountSkuId -TenantName $TenantName

      #Getting License Paths
      [System.Collections.ArrayList]$LicensePath = @()

      if($LicensesTab[$i].GroupsAssigningLicense){
      foreach ($Guid in $LicensesTab[$i].GroupsAssigningLicense.guid){

      if($Guid -eq $User.ObjectId.Guid){
      $LicensePath.Add(“Direct”) | Out-Null
      }
      else {
      $LicensePath.Add((Get-MsolGroup -ObjectId $Guid).DisplayName) | Out-Null
      }
      }
      }
      else{
      $LicensePath.Add(“Direct”) | Out-Null
      }

      Write-Host $LicensePath
      Write-Host “$LicensePlan : $($LicensePath.ToArray() -join “,”)” -ForegroundColor Yellow #$([String]::Join(“,”,$LicensePath.ToArray()))
      New-Object -TypeName PSObject -Property @{
      “UserPrincipalName” = $UPN
      “LicensePlan” = $LicensePlan
      “AssignmentPath” = $($LicensePath.ToArray() -join “,”)
      } | Export-Csv -Path $ExportPath -Encoding UTF8 -Delimiter “;” -NoTypeInformation -Append

      $i++
      }
      while ($i -ne $LicTabCount)
      }
      else {
      Write-Host “License Enabled : false” -ForegroundColor Red
      New-Object -TypeName PSObject -Property @{
      “UserPrincipalName” = $UPN
      “LicensePlan” = “”
      “AssignmentPath” = “”
      } | Export-Csv -Path $ExportPath -Encoding UTF8 -Delimiter “;” -NoTypeInformation -Append
      }

      }

      End{
      Write-Host “”
      Write-Host “## Data Processing ended on $(Get-Date)” -ForegroundColor Blue
      }

      }

      “upn1″,”upn2” | Get-LAPATH -ExportPath “c:\file.csv”

      Like

Leave a Reply to Chitra Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s