In this blog post, I will describe how the current licensing works in D365FO and introduce an open-source X++ utility that allows you to track the actual usage of elements and compare it with the elements assigned to users via user roles.
At first, the new licensing model may seem confusing. For example, what does "Entitled" or "not Entitled" mean? Here, I will describe my journey to understanding it.
The legacy model relied on AOT properties for MenuItems. For example, opening the WHSLoadTable MenuItem in Visual Studio shows two properties: one for the read-only license, and another for the write license.
This model obviously couldn't cover all the complexities of the current license model (e.g., whether you have Finance, SCM, or both). As a result, Microsoft released a new model where they store all the license information on their servers and provide it to users in Licensing* tables. The data for these tables is calculated internally by Microsoft services and periodically (e.g., every 8 hours) synchronized with the Tier 2 or PROD environments. In this model, all custom menu items are treated as Teams licenses.
Here are the license properties for the same menu item under the new model.
The logic is now different: if a user has Read access to this WHSLoadTable menu, they must have one of the 7 specified licenses. If they have Write access, they must have an SCM or SCM Premium license. This is exactly what "Entitled" means.
Microsoft provides a form "Licenses usage summary" which displays the results of the above query, but in a different level of granularity (Role - Duty - Privilege)
There are special roles that are exempt from the license report:
After familiarizing yourself with the "Licenses usage summary" form, I also recommend reading this series of articles by André Arnaud de Calavon, who has done a fantastic job of explaining various security topics. This will give you a solid foundation in the new licensing model.
There are several companies that focus on D365FO security and licensing optimization. When I originally asked a question about user logging on LinkedIn, I received a lot of insightful comments. I've saved them here for reference:
André Arnaud de Calavon / Next365 — D365 expert and consultant, probably the top writer regarding security topics. Link: André Arnaud de Calavon
D365RoleSecure / NoirSoft — D365FO security and licensing-focused tool. Link: NoirSoft / D365RoleSecure
Fastpath Assure / Alex Meyer — Security, audit, compliance, and D365FO licensing governance. Link: Fastpath Assure
Marco Romano / IT|Fandango — D365 F&O consultant offering licensing/right-sizing assessment services. Link: IT|Fandango
XPLUS Process Discovery / Anthonio Dixon — User activity and process discovery for D365, with license optimisation angle. Link: XPLUS Process Discovery
The main limitation with Microsoft's standard solution is that it doesn't provide an actual activity-based license usage report.
Consider a simple scenario: 10 users share a single role. This role contains 100 menu items that only require a Teams license, and one menu item that requires an Activity license. How can we determine which of these 10 users are actually using that specific Activity menu item?
The License usage log tool was built to fill this gap and answer exactly these types of questions. It can be downloaded from GitHub and deployed to your PROD environment using your standard X++ pipeline.
After installation, you need to enable element usage logging. You have two options:
You should run this for a couple of weeks in your PROD environment to collect meaningful usage data.
The following events are logged:
One of the main challenges of license monitoring is distinguishing whether a user only viewed a form or if they actually modified data. We can gather modification events from two sources:
The tool allows you to specify a period (e.g., the last 90 days) and process the modification information from the two sources mentioned above.
The next challenge is linking the form to a list of tables. The License tool automatically calculates this by linking all form DataSources with the corresponding MenuItem, but you can also manually correct these links if needed.
The License log form includes a couple of useful service functions:
It also includes a couple of custom recalculated tables, which are primarily used for tracking and debugging:
After collecting the element usage log and calculating the data modification information, open the User license report tab and click Refresh data. The report will compare each user’s currently assigned license with the highest license tier required based on their captured system usage.
The report consists of two sections: a header and lines.
The header contains one row per user and provides their licensing status:
The lines section details the individual securable objects behind a selected user's result, explaining exactly why they fall into a specific license tier:
This report evaluates users by comparing their Assigned license level (the "License" column) with their Actual system usage (the "Usage log license" column), based on captured daily activity and entitlement objects.
Let's review the possible analysis scenarios based on the Compare status field:
The assigned license accurately corresponds to the user’s actual system activity.
Technical meaning:
Example 1
In this example, we can see that the user accesses the Work and Waves forms and actually writes to the relevant tables. This legitimately requires a Supply Chain Management license; it cannot be further optimized.
Example 2
This example is a bit different. The user only runs the TMSPACKINGLIST report. Microsoft recently changed this report to require an Enterprise-level license (it previously only required an Activity license). Since the high license requirement is caused by this single report, it presents an opportunity to reduce costs by developing a custom report or providing the required data through a different channel.
A common question here is: Can we just duplicate the standard MenuItem and use our custom copy instead? According to the D365 licensing guide, this practice constitutes "Multiplexing," and still requires the original underlying license to be applied.
The user accesses functionality corresponding to their assigned license, but no write operations were captured for the related tables.
Technical meaning:
Example
The user accesses the Waves form, but there is no confirmed record of them writing to its underlying tables. While this requires further investigation, it highlights an opportunity to lower their access to this form to read-only, which could potentially reduce their required license level down to a Teams license.
The user’s assigned license is higher than what their actual logged system activity.
Technical meaning:
Example
In this case, the user is assigned a full SCM license. However, the usage log reveals they only use two forms that require an Activity license. This makes them a strong candidate for a permissions review to right-size their licensing.
The user has an assigned license, but zero recorded system activity.
Technical meaning:
The user is assigned an SCM license, but no logging activity was recorded. There are a few possibilities here: the user may no longer require system access and should be disabled; or, the user might be a high-level manager who only needs periodic read access, or could perhaps be assigned a different appropriate role instead of holding an unused premium license.
For a fast executive overview, you can copy the report's header data into Excel, then pass it to ChatGPT alongside this prompt to generate a helpful written summary for stakeholders.
A license usage log utility provides insights into how users interact with the system by producing a usage report that compares the required license usage based on actual activity against the currently allocated licenses based on user roles.
The tool is open source and can be downloaded from GitHub.
I look forward to your feedback on it. Specifically:
For general questions, please use the original post on LinkedIn. For bug reports or feature requests, please use the GitHub issue tracker.
I hope you found this post helpful. As always, if you have any suggestions for improvements or questions regarding this implementation, please don't hesitate to reach out.
Similar posts: