Script Repository


Send notification if number of unused Microsoft 365 licenses falls below limit

December 15, 2020
7598

The script sends an email notification if the number of unused licenses for the specified license plans enabled in any of Microsoft 365 (Office 365) tenants falls below a specific limit. You can use the script to receive an email notification when the number of available Microsoft 365 (Office 365) licenses is too low and have time to take appropriate action.

To receive notifications when the limit is reached, you need to create a Scheduled Task configured for the Domain-DNS object type. To add the script to a Scheduled Task, use the Run a program or PowerShell script action.

Parameters:

  • $limit - Specifies the minimum number of unused licenses. The script will send an email if the number of available licenses is below this limit.
  • $skus - Specifies the SKU Part Numbers of the licenses to check. If set to NULL, the script will check all the enabled licenses.
  • $to - Specifies email addresses of the email notification recipient(s).
  • $subject - Specifies the email notification subject.
  • $reportHeader - Specifies the email notification header.
  • $htmlTableCoulmns - Specifies column headers for the table that contains details on the number of Microsoft 365 (Office 365) licenses.
  • $reportFooter - Specifies the email notification footer.

To get the SKU Part Number of a license plan in Adaxes:

  1. In Adaxes Administration Console, expand the service node that represents your Adaxes service.
  2. Navigate to Configuration\Cloud Services and select Microsoft 365.
  3. Double-click the Microsoft 365 (Office 365) tenant to which the license belongs.
  4. Click the necessary license plan. The SKU Part Number is displayed below the Display Name field.
Edit Remove
PowerShell
$limit = 5 # TODO: modify me
$skus = @("ENTERPRISEPREMIUM", "ENTERPRISEPACK") # TODO: modify me

# E-mail settings
$to = "recipient@domain.com" # TODO: modify me
$subject = "List of Microsoft 365 plans that have $limit or less licenses available" # TODO: modify me
$reportHeader = "<h2>List of Microsoft 365 plans that have $limit or less licenses available</h2>"
$htmlTableColumns = "
<table border='1'>
    <tr>
        <th>License Plan</th>
        <th>Total Licenses</th>
        <th>Unused Licenses</th>
    </tr>
" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

# Find all tenants
$microsoft365TenantsPath = $Context.GetWellKnownContainerPath("CloudServicesO365")
$searcher = $Context.BindToObject($microsoft365TenantsPath)
$searcher.SearchFilter = "(objectClass=adm-O365Tenant)"
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500

try
{
    $searchResultIterator = $searcher.ExecuteSearch()
    $searchResults = $searchResultIterator.FetchAll()
    
    $report = $NULL
    foreach ($searchResult in $searchResults)
    {
        # Bind to the tenant
        $tenant = $Context.BindToObject($searchResult.AdsPath)
        
        # Check licenses
        $htmlTable = $NULL
        foreach ($sku in $tenant.Skus)
        {
            if (($skus -ne $NULL) -and ($skus -notcontains $sku.SkuPartNumber))
            {
                continue
            }
            
            $difference = $sku.TotalUnits - $sku.ConsumedUnits
            if ($difference -gt $limit)
            {
                continue
            }
            
            if ($htmlTable -eq $NULL)
            {
                $htmlTable += "<h3>$($tenant.TenantName)</h3>$htmlTableColumns"
            }
            
            $htmlTable += "<tr><td>$($sku.DefaultDisplayName)</td><td>$($sku.TotalUnits)</td><td>$difference</td></tr>"
        }
        if ($htmlTable -eq $NULL)
        {
            continue
        }
        
        $htmlTable += "</table>"
        $report += $htmlTable
    }
    
    if ($report -eq $NULL)
    {
        return # There are no licenses in any tenant that are below the limit
    }
    
    # Build report
    $html = $reportHeader + $report + $reportFooter
    
    # Send mail
    $Context.SendMail($to, $subject, $NULL, $html)
}
finally
{
    # Release resources
    $searchResultIterator.Dispose()
}


Comments ( 17 )
avatar
Dave T.
May 13, 2019
Can the script be modified to only return values for the select products only or a specific subset of products?
O365_BUSINESS_ESSENTIALS
Office 365 Business
avatar
Support
May 14, 2019

Hello Dave,

Yes, it is possible. We have updated the script with the possibility to specify SKU Part Numbers of the licenses to check.

avatar
Amz
Jul 29, 2019
Running the script throws an error saying "You cannot call a method on null valued expression". Please help me fix. Have set $skus to NULL to check for all the license enabled in our tenant
avatar
Support
Jul 30, 2019

Hello,

Could you, please, send us (support[at]adaxes.com) the script you are using with all the modifications and a screenshot of the full error message you are getting?

avatar
GRes
Mar 05, 2020
Hello, I am receiving the same message as Amz. Did you update the script to fix this issue? Thanks.
avatar
Support
Mar 05, 2020

Hello,

We were not able to reproduce the issue and the script works just fine. Could you, please, send us (support[at]adaxes.com) the script you are using with all the modifications and a screenshot of the full error message you are getting?

Also, please, specify how exactly the script is executed. A screenshot of the Scheduled Task that runs the script would be very helpful.

avatar
Jack
Dec 03, 2020
This worked great. Thank you!
avatar
Daniel
Sep 19, 2021
Can we make it not send the email at all if all SKUs are good on the counts?
We don't want a email at all unless it falls below on something.
avatar
Support
Sep 22, 2021
Hello Daniel,

Sorry for the confusion, but we are not sure what exactly you mean. The current script sends an email notification only if at least one of the specified Microsoft 365 licenses falls below the limit. If none of the licenses fall below the limit no email notification is send. If the email is still sent, please, make sure that you are using the exact above script without any modifications.
avatar
Daniel
Oct 13, 2021
Yes sorry its working as expected. But is there a way to add multiple TO emails?
avatar
Support
Oct 13, 2021
Hello Daniel,

Yes, it is possible. Just specify all the addresses in the $to variable:

$to = "recipient@domain.com, recipient2@domain.com"
avatar
Raul
Oct 19, 2021
How can I set different limits for different skus within the same email? or will it require a separate task for each limit?
avatar
Support
Oct 20, 2021
Hello Raul,

Unfortunately, there is no such possibility in the current script. However, it is possible to modify the script to meet your needs. Please, describe the desired behavior in all the possible details with live examples.
avatar
Raul
Oct 20, 2021
What we would like is a way to specify different limits that the script can select from based on limit quantity. So if there is one of the SKUs under $limit=10 is true, then it generates an email based on that, if there's one under the $limit=5 then it also generates one based on that, and so forth. I tried the following on my script, but it only executed it for $limit=3 and ignored the rest above:

$limit = 10
$skus = @("EXCHANGESTANDARD","MCOMEETADV","SPE_E3","IDENTITY_THREAT_PROTECTION","MCOEV","POWER_BI_PRO")

$limit = 5
$skus = @("EXCHANGEENTERPRISE","POWER_BI_PRO","PROJECTPROFESSIONAL")

$limit = 3
$skus = @("VISIOCLIENT","MEETING_ROOM","PROJECT_P1")
avatar
Support
Oct 21, 2021
Hello Raul,

Thank you for clarifying. What about the email recipients? Should they be the same for all licenses?

Also, please, specify how Microsoft 365 licenses should be identified in the email notifications. Should that be the licenses SKU Part Numbers or their display names as specified in the tenant settings?

Any additional details will be much appreciated.
avatar
Raul
Oct 21, 2021
Hi Support,

For our case only one recipient is needed; however, I can see how this could be really useful to be able to specify recipients to specific limits.

For identification purposes, the display names of each SKU are good enough. If there's a way to also include the SKU part number along with the display name then I think this would be perfect.

We also do manage a separate instance of Adaxes and MS tenant. I figured this will simply have to be managed separately with a script on that Adaxes admin console? Or is there a possibility to apply all of the above to multiple tenants from the same script? No big deal if this is not possible, but less management is always better :)
avatar
Support
Oct 21, 2021
Hello Raul,

> For our case only one recipient is needed; however, I can see how this could be really useful to be able to specify recipients to specific limits.
We will update the script so that it is possible to specify a separate recipient for each license.

> We also do manage a separate instance of Adaxes and MS tenant.
If you have separate instances (not sharing common configuration) of Adaxes service you will need to configure the script execution separately on each of them.

> Or is there a possibility to apply all of the above to multiple tenants from the same script?
The script check licenses in all the Microsoft 365 tenants registered for the Adaxes service the script is executed by. If you need information about tenants included into the email, please, provide a sample email notification.
Leave a comment

Related Scripts