get-O365LicenseOverview.ps1

<#PSScriptInfo
.VERSION 1.0
.GUID ad23a25e-d924-42a1-b9bf-30e5ef65c170
.AUTHOR
 Maarten Peeters - Cloud Securitea - https://www.cloudsecuritea.com
.COMPANYNAME
 Cloud Securitea
.COPYRIGHT
.TAGS
 Subscriptions, licenses, office365
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES
 MSOnline
.RELEASENOTES
 Version 1.0: Original published version.
#>
 

<#
.SYNOPSIS
 Quickly generate an Office 365 subscription and license overview
 
.DESCRIPTION
 This script will generate a HTML file to list the following:
 List of all subscriptions
 List of all SKU's combined
 List of all groups who have licenses connected to them
 List of all unlicensed users who have no role assigned
 List of all unlicensed users who have a role assigned
 List of all licensed users who have a role assigned
 List of all licensed users who get their license directly
 List of all licensed users who get their license via group assignement
 
.PARAMETER LogPath
 Enter the full path to store the HTML report of the Office 365 subscription and license overview
 For example: C:\Install
 
.EXAMPLE
 Get-O365LicenseOverview.ps1 -LogPath "C:\Install"
 
 .NOTES
 Version: 1.0
 Author: Maarten Peeters
 Creation Date: 04-09-2019
 Purpose/Change: Quickly generate an overview of Office 365 Subscriptions and licenses
#>


param(
    [Parameter(mandatory=$true)]
    [string] $LogPath
)

try{
    #Verify if MSOnline Module is available
    if (Get-Module -ListAvailable -Name MSonline) {
        #Import MSOnline Module
        import-module MSOnline -ErrorAction SilentlyContinue

        #Test if logpath exists
        If(Test-Path $LogPath) { 
            #Start script
            Try{
                #Object collections
                $subscriptionCollection = @()
                $accountSkuCollection = @()
                $licensedGroupCollection = @()
                $usersWithRolesCollection = @()
                $usersLicensedByGroupCollection = @()
                $usersLicensedDirectlyCollection = @()
                $usersUnlicensedNoRoleCollection = @()
                $usersUnlicensedWithRoleCollection = @()
                $usersLicensedWithRoleCollection = @()

                #Connect to the correct O365 Tenant
                Connect-MsolService

                #Retrieve all subscriptions and place this information in an object
                $subscriptions = Get-MsolSubscription
                foreach($subscription in $subscriptions){
                    $subscriptionCollection += new-object psobject -property @{ObjectId=$subscription.ObjectId;SkuPartNumber=$subscription.SkuPartNumber;Status=$subscription.Status;TotalLicenses=$subscription.TotalLicenses}
                }

                #Retrieve all account Sku's and place this information in an object
                $accountSkus = Get-MsolAccountSku
                foreach($accountSku in $accountSkus){
                    $accountSkuCollection += new-object psobject -property @{SkuPartNumber=$accountSku.SkuPartNumber;ActiveUnits=$accountSku.ActiveUnits;ConsumedUnits=$accountSku.ConsumedUnits}
                }

                #Retrieve group which have licenses assigned to them and place this information in an object
                $licensedGroups = Get-MsolGroup | Where-Object {$_.licenses -ne ""}
                foreach($licensedGroup in $licensedGroups){
                    $groupMembers = (Get-MsolGroupMember -GroupObjectId $licensedGroup.ObjectId).count
                    $licenses = $licensedGroup.licenses
                    foreach($license in $licenses){
                        $licensedGroupCollection += new-object psobject -property @{ObjectID=$licensedGroup.objectID;DisplayName=$licensedGroup.DisplayName;Members=$GroupMembers;license=$license.SkuPartNumber}
                    }
                }

                #Retrieve all users who have roles assigned
                $roles = Get-MsolRole
                foreach($role in $roles){
                    $members = Get-MsolRoleMember -RoleObjectId $role.ObjectId
                    foreach($member in $members){
                        $usersWithRolesCollection += new-object psobject -property @{DisplayName=$member.DisplayName;RoleName=$role.name}
                    }
                }

                #Retrieve all users and place them in their appropiate collection
                $users = Get-MsolUser | Sort-Object DisplayName

                foreach ($user in $users){
                    #check if synced account
                    if($user.ImmutableId -eq $null){
                        $synced = "False"
                    }
                    else{
                        $synced = "False"
                    }

                    #Unlicensed users
                    if ($user.isLicensed -eq $false){
                        #if the user has an admin role or not
                        $adminRole = "no"
                        foreach($userWithRoles in $usersWithRolesCollection){
                            if($user.DisplayName -eq $userWithRoles.DisplayName){
                                $adminRole = "yes"
                            }
                        }
                        if($adminRole -eq "no"){
                            $usersUnlicensedNoRoleCollection += new-object psobject -property @{DisplayName=$user.DisplayName;UserType=$user.UserType;UPN=$user.userprincipalname;License=$user.isLicensed;Admin="False";BlockCredential=$user.BlockCredential;Synced=$Synced}
                        }
                        else{
                            $usersUnlicensedWithRoleCollection += new-object psobject -property @{DisplayName=$user.DisplayName;UserType=$user.UserType;UPN=$user.userprincipalname;License=$user.isLicensed;Admin="True";BlockCredential=$user.BlockCredential;Synced=$Synced}
                        }
                    }

                    #Licensed with admin role
                    if ($user.isLicensed -eq $true){
                        #if the user has an admin role or not
                        $adminRole = "no"
                        foreach($userWithRoles in $usersWithRolesCollection){
                            if($user.DisplayName -eq $userWithRoles.DisplayName){
                                $adminRole = "yes"
                            }
                        }
                        if($adminRole -eq "yes"){
                            $usersLicensedWithRoleCollection += new-object psobject -property @{DisplayName=$user.DisplayName;UserType=$user.UserType;UPN=$user.userprincipalname;License=$user.isLicensed;Admin="True";BlockCredential=$user.BlockCredential;Synced=$Synced}
                        }
                    }

                    #Licensed users and verify if the license is coming from a group or directly
                    if ($user.isLicensed -eq $true){
                        $licenses = $user.licenses
                        
                        foreach($license in $licenses){
                            #You can use Groups Assigning License but I noticed that if it's not assigned via a group it will be the users GUID. I will verify the group with the earlier collection.
                            $groupAssignedFound = "no"
                            $groupAssigned = ""
                            foreach($groupAssigningLicense in $license.GroupsAssigningLicense){
                                $groupAssigned = $licensedGroupCollection | where-object {$_.ObjectID -eq $groupAssigningLicense.GUID}
                                if($groupAssigned){
                                    $groupAssignedFound = "yes"
                                }
                            }
                            
                            if ($groupAssignedFound -eq "no"){
                                $usersLicensedDirectlyCollection += new-object psobject -property @{DisplayName=$user.DisplayName;UserType=$user.UserType;UPN=$user.userprincipalname;License=$license.accountsku.skupartnumber;BlockCredential=$user.BlockCredential;Synced=$Synced}
                            }
                            else{
                                $usersLicensedByGroupCollection += new-object psobject -property @{DisplayName=$user.DisplayName;UserType=$user.UserType;UPN=$user.userprincipalname;License=$license.accountsku.skupartnumber;BlockCredential=$user.BlockCredential;Synced=$Synced}
                            }
                        }
                    }
                }
                
                #We now have our collections so we are building the HTML page to get a direct view
                #List of all subscriptions
                $article = "<h2>List of all subscriptions</h2>"
                $article += "<table>
                            <tr>
                                <th>ObjectId</th>
                                <th>SkuPartNumber</th>
                                <th>Status</th>
                                <th>TotalLicenses</th>
                            </tr>"

                
                foreach($subscription in $subscriptionCollection){
                $article += "<tr>
                                <td>$($subscription.ObjectId)</td>
                                <td>$($subscription.SkuPartNumber)</td>
                                <td>$($subscription.Status)</td>
                                <td>$($subscription.TotalLicenses)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all SKU's combined
                $article += "<h2>List of all SKU's combined</h2>"
                $article += "<table>
                            <tr>
                                <th>SkuPartNumber</th>
                                <th>ActiveUnits</th>
                                <th>ConsumedUnits</th>
                            </tr>"

                
                foreach($accountSku in $accountSkuCollection){
                $article += "<tr>
                                <td>$($accountSku.SkuPartNumber)</td>
                                <td>$($accountSku.ActiveUnits)</td>
                                <td>$($accountSku.ConsumedUnits)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all groups who have licenses connected to them
                $article += "<h2>List of all groups who have licenses connected to them</h2>"
                $article += "<table>
                            <tr>
                                <th>ObjectID</th>
                                <th>DisplayName</th>
                                <th>Members</th>
                                <th>license</th>
                            </tr>"

                
                foreach($licensedGroup in $licensedGroupCollection){
                $article += "<tr>
                                <td>$($licensedGroup.ObjectID)</td>
                                <td>$($licensedGroup.DisplayName)</td>
                                <td>$($licensedGroup.Members)</td>
                                <td>$($licensedGroup.license)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all unlicensed users who have no role assigned
                $article += "<h2>List of all unlicensed users who have no role assigned</h2>"
                $article += "<table>
                            <tr>
                                <th>DisplayName</th>
                                <th>UserType</th>
                                <th>UPN</th>
                                <th>license</th>
                                <th>Admin</th>
                                <th>BlockCredential</th>
                                <th>Synced</th>
                            </tr>"

                
                foreach($usersUnlicensedNoRole in $usersUnlicensedNoRoleCollection){
                $article += "<tr>
                                <td>$($usersUnlicensedNoRole.DisplayName)</td>
                                <td>$($usersUnlicensedNoRole.UserType)</td>
                                <td>$($usersUnlicensedNoRole.UPN)</td>
                                <td>$($usersUnlicensedNoRole.license)</td>
                                <td>$($usersUnlicensedNoRole.Admin)</td>
                                <td>$($usersUnlicensedNoRole.BlockCredential)</td>
                                <td>$($usersUnlicensedNoRole.Synced)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all unlicensed users who have a role assigned
                $article += "<h2>List of all unlicensed users who have a role assigned</h2>"
                $article += "<table>
                            <tr>
                                <th>DisplayName</th>
                                <th>UserType</th>
                                <th>UPN</th>
                                <th>license</th>
                                <th>Admin</th>
                                <th>BlockCredential</th>
                                <th>Synced</th>
                            </tr>"

                
                foreach($usersUnlicensedWithRole in $usersUnlicensedWithRoleCollection){
                $article += "<tr>
                                <td>$($usersUnlicensedWithRole.DisplayName)</td>
                                <td>$($usersUnlicensedWithRole.UserType)</td>
                                <td>$($usersUnlicensedWithRole.UPN)</td>
                                <td>$($usersUnlicensedWithRole.license)</td>
                                <td>$($usersUnlicensedWithRole.Admin)</td>
                                <td>$($usersUnlicensedWithRole.BlockCredential)</td>
                                <td>$($usersUnlicensedWithRole.Synced)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all licensed users who have a role assigned
                $article += "<h2>List of all licensed users who have a role assigned</h2>"
                $article += "<table>
                            <tr>
                                <th>DisplayName</th>
                                <th>UserType</th>
                                <th>UPN</th>
                                <th>license</th>
                                <th>Admin</th>
                                <th>BlockCredential</th>
                                <th>Synced</th>
                            </tr>"

                
                foreach($usersLicensedWithRole in $usersLicensedWithRoleCollection){
                $article += "<tr>
                                <td>$($usersLicensedWithRole.DisplayName)</td>
                                <td>$($usersLicensedWithRole.UserType)</td>
                                <td>$($usersLicensedWithRole.UPN)</td>
                                <td>$($usersLicensedWithRole.license)</td>
                                <td>$($usersLicensedWithRole.Admin)</td>
                                <td>$($usersLicensedWithRole.BlockCredential)</td>
                                <td>$($usersLicensedWithRole.Synced)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all licensed users who get their license directly
                $article += "<h2>List of all licensed users who get their license directly</h2>"
                $article += "<table>
                            <tr>
                                <th>DisplayName</th>
                                <th>UserType</th>
                                <th>UPN</th>
                                <th>license</th>
                                <th>BlockCredential</th>
                                <th>Synced</th>
                            </tr>"

                
                foreach($usersLicensedDirectly in $usersLicensedDirectlyCollection){
                $article += "<tr>
                                <td>$($usersLicensedDirectly.DisplayName)</td>
                                <td>$($usersLicensedDirectly.UserType)</td>
                                <td>$($usersLicensedDirectly.UPN)</td>
                                <td>$($usersLicensedDirectly.license)</td>
                                <td>$($usersLicensedDirectly.BlockCredential)</td>
                                <td>$($usersLicensedDirectly.Synced)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                #List of all licensed users who get their license via group assignement
                $article += "<h2>List of all licensed users who get their license via group assignement</h2>"
                $article += "<table>
                            <tr>
                                <th>DisplayName</th>
                                <th>UserType</th>
                                <th>UPN</th>
                                <th>license</th>
                                <th>BlockCredential</th>
                                <th>Synced</th>
                            </tr>"

                
                foreach($usersLicensedByGroup in $usersLicensedByGroupCollection){
                $article += "<tr>
                                <td>$($usersLicensedByGroup.DisplayName)</td>
                                <td>$($usersLicensedByGroup.UserType)</td>
                                <td>$($usersLicensedByGroup.UPN)</td>
                                <td>$($usersLicensedByGroup.license)</td>
                                <td>$($usersLicensedByGroup.BlockCredential)</td>
                                <td>$($usersLicensedByGroup.Synced)</td>
                            </tr>"

                }
                
                $article += "</table>"
                
                $date = get-date
                $today = $date.ToString("ddMMyyyy_HHmm")
                $LogPath = Join-Path $LogPath "HTMLSubscriptionReport_$($today).html"    
                
                #Head
                $head = "
                    <html xmlns=`"http://www.w3.org/1999/xhtml`">
                        <head>
                            <style>
                                @charset `"UTF-8`";
 
                                @media print {
                                    body {-webkit-print-color-adjust: exact;}
                                }
                     
                                div.container {
                                    width: 100%;
                                    border: 1px solid gray;
                                }
                                 
                                header {
                                    padding: 0.1em;
                                    color: white;
                                    background-color: #000033;
                                    color: white;
                                    clear: left;
                                    text-align: center;
                                    border-bottom: 2px solid #FF0066
                                }
                                 
                                footer {
                                    padding: 0.1em;
                                    color: white;
                                    background-color: #000033;
                                    color: white;
                                    clear: left;
                                    text-align: center;
                                    border-top: 2px solid #FF0066
                                }
 
                                article {
                                    margin-left: 20px;
                                    min-width:600px;
                                    min-height: 600px;
                                    padding: 1em;
                                }
                                 
                                th{
                                    border:1px Solid Black;
                                    border-Collapse:collapse;
                                    background-color:#000033;
                                    color:white;
                                }
                                 
                                th{
                                    border:1px Solid Black;
                                    border-Collapse:collapse;
                                }
 
                            </style>
                        </head>
                    "

                    
                    #Header
                    $date = (get-date).tostring("dd-MM-yyyy")
                    $header = "
                        <h1>Subscriptions Report</h1>
                        <h5>$($date)</h5>
                    "

                    
                    #Footer
                    $Footer = "
                        Copyright &copy;
                    "

                    
                    #Full HTML
                    $HTML = "
                        $($Head)
                        <body class=`"Inventory`">
                            <div class=`"container`">
                                <header>
                                    $($Header)
                                </header>
                                 
                                <article>
                                    $($article)
                                </article>
                                         
                                <footer>
                                    $($footer)
                                </footer>
                            </div>
                        </body>
                        </html>
                    "
 
                    add-content $HTML -path $LogPath

                    Write-Host "Office 365 subscription and license overview created at $($LogPath), it will also open automatically in 5 seconds" -foregroundcolor green

                    start-sleep -s 5
                    Invoke-Item $LogPath
            }
            catch{
                write-host "Error occurred: $($_.Exception.Message), please post this error on https://www.cloudsecuritea.com" -foregroundcolor red
            }
        } Else { 
            Write-Host "The path $($LogPath) could not be found. Please enter a correct path to store the Office 365 subscription and license overview" -foregroundcolor yellow
        }
    } else {
        Write-Host "MSOnline module not loaded. Please install the MSOnline module with Install-Module MSOnline" -foregroundcolor yellow
    }
}
catch{
    write-host "Error occurred: $($_.Exception.Message)" -foregroundcolor red
}