Tracking Licensing Costs for Microsoft 365 Tenants

Microsoft 365 Licensing Report Details Costs Per User to Find Optimizations

Recently, I released an update to my Microsoft 365 Licensing Report PowerShell script to include the ability to assign costs to user accounts. The idea is to give administrators information about how much the cumulative annual license charges are for each account. Combining cost data with insight about account activity in a tenant (generated with the user activity report script or by reference to the individual workload usage reports in the Microsoft 365 admin center), administrators can figure out if users have the right licenses they need to work and no licenses are assigned to inactive accounts.

Managing the cost of Office 365 and Microsoft 365 licenses has always been important. As Microsoft puts more focus on driving revenue through high-priced add-ons such as Teams Premium ($120/year) and Copilot for Microsoft 365 ($360/year), it’s even more essential to keep close tabs on license assignments. There’s no point in assigning a Copilot license to someone who’s inactive or whose usage pattern indicates that they might not take advantage of the license. No one is rewarded for overspending on licenses.

Adding Cost by Department and Cost by Country to the Microsoft 365 Licensing Report

Almost immediately after releasing the updated script, calls came in to ask if it was possible to generate an analysis of licensing cost by country and by department. My initial response was “sure” and I set to figuring out the best way to implement the change.

Because the report script tracks license costs per user, the simple method is to:

  • Find the sets of departments and countries in user accounts.
  • For each department (or country), calculate the sum of license costs.
  • Include the information in the report.

The same approach works to analyze license costs for any user account property fetched by the initial Get-MgUser command at the start of the script. If the set of regular account properties don’t work for your organization, you could use an Exchange custom attribute to store the required values. For instance, you could include a cost center number in a custom attribute. Here’s how to access Exchange custom attributes with Get-MgUser. You’ll need to extract the information from the custom attribute before you can use it in the script.

The Problems Caused by Inaccurate Directory Data

The obvious problem is that sometimes the properties of user accounts don’t include a department or country. Account properties should hold accurate properties, but unfortunately this sometimes doesn’t happen because administrators fail to add properties to accounts, or a synchronization process linking a HR system to Entra ID encounters problems, or something else conspires to erode directory accuracy. The point is that inaccurate or missing user account properties result in bad license accounting.

The first order of business is therefore to validate that the account properties that you want to use for license cost reporting exist and are correct. This article explains how to detect user accounts with missing properties. Making sure that properties are accurate requires an extra level of review. The value of the country property assigned to user accounts shouldn’t change frequently, but properties like department and office might.

Reporting Licensing Costs for Country and Department

After making sure that all the necessary user account properties are in place (and accurate), the code to generate cost analyses based on department and country worked like a dream. The script also required an update to insert the new data into the output report, including warnings for administrators when costs cannot be attribute to countries or departments because of missing account properties. Figure 1 shows the result.

Costs for departments and countries shown in Microsoft 365 Licensing Report.
Figure 1: Costs for departments and countries shown in Microsoft 365 Licensing Report

The code changes are in version 1.6 of the report script, which you can download from GitHub. If you haven’t run the script before, make sure that you read the previous Practical365.com articles to understand how the script works and how to generate the two (SKU and service plan) CSV files used by the script.

Remember that this script is intended to demonstrate the principles of interacting with and interpreting Entra ID user account and license information with the Microsoft Graph PowerShell SDK. It’s not intended to be a bulletproof license cost management solution. Have fun with PowerShell!


Learn how to exploit the data available to Microsoft 365 tenant administrators (like licensing information) through the Office 365 for IT Pros eBook. We love figuring out how things work.

4 Replies to “Tracking Licensing Costs for Microsoft 365 Tenants”

    1. There are details in the script telling you how to generate the SKU and service plan CSVs. The original article (on Practical365.com) explains how by running a script (also available from GitHub). I’ve tweaked the text to make this more obvious.

      There’s also details in the script:

      # This step depends on the availability of some CSV files generated to hold information about the product licenses used in the tenant and
      # the service plans in those licenses. See https://github.com/12Knocksinna/Office365itpros/blob/master/CreateCSVFilesForSKUsAndServicePlans.PS1
      # for code to generate the CSVs. After the files are created, you need to edit them to add the display names for the SKUs and plans.
      # Build Hash of Skus for lookup so that we report user-friendly display names – you need to create these CSV files from SKU and service plan
      # data in your tenant.

  1. hello Tony many thanks for your work
    i added the price et Currency (EUR) for me, but the script don’t find the price value in the files SKUDATAcomplete.csv could you please provide an template CSV files with price for test

    1. You’ve got to populate the CSV file with the prices your organization pays Microsoft for licenses. I have no knowledge of what you pay per license.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.