Entra / Microsoft 365 · Exchange Online
Check shared mailboxes for MDO licensing
A script to check the Entra ID accounts used for shared mailboxes to figure out if they should be licensed for Microsoft Defender for Office 365 (MDO).
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -AppId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $TenantId = "",[string] $AppId = "",[int] $LookbackDays = 10,[string] $DestinationEmailAddress = "")$Thumbprint = "8CD4AD070C7447BA767EAB5DA659A02E6411BB80"# Connect to the Microsoft GraphWrite-Output "Connecting to Microsoft Graph..."Connect-MgGraph -AppId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint# Get the tenant information and the list of verified domains for the tenant$TenantInfo = Get-MgOrganization$DefaultDomain = $TenantInfo.VerifiedDomains | Where-Object {$_.IsDefault -eq $true} | Select-Object -ExpandProperty Name# Find the set of verified domains for the tenant that we can use to check against incming email[array]$Domains = Get-MgDomain -AllIf ($Domains.Count -eq 0) {Write-Output "No verified domains found in the tenant. Exiting."Break} Else {[array]$VerifiedDomains = $Domains | Where-Object {$_.IsVerified -eq $true} | Select-Object -ExpandProperty Id}# Connect to Exchange Online in app-only mode - before this can happen, the app must be assigned the manage Exchange as app permission and# be assigned the Exchange administrator role for the tenantWrite-Output "Connecting to Exchange Online..."Connect-ExchangeOnline -CertificateThumbprint $Thumbprint -AppId $AppId -Organization $DefaultDomain -ShowBanner:$false# Define the MDO service plan IDs for P1 and P2 along with the Exchange Online Plan 2 plan. The MDO Plan 1 is onbly used for Microsoft 365 SME tenants.$MDOPlan1 = "f20fedf3-f3c3-43c3-8267-2bfdd51c0939"$MDOPlan2 = "8e0c0a52-6a6c-4d40-8370-dd62790dcd70"$EXOPlan2 = "efb87545-963c-4e0d-99df-69c6916d9eb0"Write-Output "Checking shared mailboxes for MDO license requirements..."# Get the shared mailboxes[array]$Mbx = Get-ExoMailbox -RecipientTypeDetails SharedMailbox -ResultSize UnlimitedIf ($Mbx) {Write-Output ("Fetched {0} shared mailboxes from the tenant." -f $Mbx.Count)} Else {Write-Output "No shared mailboxes found in the tenant. Exiting."Break}$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($M in $Mbx) {$NeedsMDO = $falseWrite-Output ("Checking shared mailbox {0}" -f $M.DisplayName)$DeliveredTraffic = $null$NeedsMDO = $false$HasMDO = $false[array]$InboxTraffic = Get-MessageTraceV2 -RecipientAddress $M.PrimarySmtpAddress -StartDate (Get-Date).AddDays(-$LookbackDays) -EndDate (Get-Date) -ResultSize 5000If ($InboxTraffic.Count -eq 0) {Write-Output ("No message trace data found for shared mailbox {0} over the last 10 days." -f $M.UserPrincipalName)Continue}$DeliveredTraffic = $InboxTraffic | Where-Object {$_.Status -eq "Delivered"}[array]$ExternalTrafficDomains = $null[int]$NumberOfExternalMessages = 0ForEach ($Message in $DeliveredTraffic) {$SenderDomain = $Message.SenderAddress.Split("@")[1].ToLower()If ($VerifiedDomains -notcontains $SenderDomain) {$NeedsMDO = $true$NumberOfExternalMessages++If ($ExternalTrafficDomains -notcontains $SenderDomain) {$ExternalTrafficDomains += $SenderDomain}}}If ($NeedsMDO -and $ExternalTrafficDomains) {[array]$AssignedPlans = Get-MgUser -UserId $M.ExternalDirectoryObjectId -Property AssignedPlans | Select-Object -ExpandProperty assignedPlans | Where-Object {$_.CapabilityStatus -eq 'Enabled'} | Select-Object -ExpandProperty ServicePlanIdIf ($MDOPlan2 -notin $AssignedPlans) {$HasMDO = $false} Else {$HasMDO = $true}If ($HasMDO) {Write-Output ("Shared mailbox {0} has an MDO license." -f $M.DisplayName)} Else {Write-Output ("Shared mailbox {0} does not have an MDO license and needs one because the mailbox has received external email from {1}" -f $M.DisplayName, ($ExternalTrafficDomains -join ", "))}If ($ExoPlan2 -in $AssignedPlans) {Write-Output ("Shared mailbox {0} has an Exchange Online Plan 2 license." -f $M.DisplayName)$EXOPlan2Licensed = $true} Else {Write-Output ("Shared mailbox {0} does not have an Exchange Online Plan 2 license." -f $M.DisplayName)$EXOPlan2Licensed = $false}$ReportLine = [PSCustomObject][Ordered]@{Mailbox = $M.DisplayNamePrimarySmtpAddress = $M.PrimarySmtpAddressNeedsMDO = $NeedsMDOHasMDO = $HasMDOHasExoPlan2License = $EXOPlan2Licensed'Count of external email' = $NumberOfExternalMessages'External Domains' = ($ExternalTrafficDomains -join ", ")}$Report.Add($ReportLine)}}# Send email with the results$MsgFrom = "PowerShell.Reports@office365itpros.com"# Build the array of a single TO recipient detailed in a hash table - change this to the appropriate recipient for your tenant$ToRecipient = @{}$ToRecipient.Add("emailAddress",@{'address'=$DestinationEmailAddress})[array]$MsgTo = $ToRecipient# Define the message subject$MsgSubject = "Important: Shared Mailboxes that need Microsoft Defender for Office 365 Licenses"# Create the HTML content$HtmlMsg = ("</body></html><p>The following <b>{0} Shared Mailboxes need Microsoft Defender for Office 365 Licenses</b> based on their email traffic over the last 10 days. Please review the information at your convenience</p>" -f $Report.Count)# Construct the message body$HtmlBody = $Report | ConvertTo-Html -As Table -PostContent "</body></html>" -Fragment$HtmlMsg = $HtmlMsg + $HtmlBody$MsgBody = @{}$MsgBody.Add('Content', "$($HtmlMsg)")$MsgBody.Add('ContentType','html')# Build the parameters to submit the message$Message = @{}$Message.Add('subject', $MsgSubject)$Message.Add('toRecipients', $MsgTo)$Message.Add('body', $MsgBody)$Message.Add("attachments", $MsgAttachments)$EmailParameters = @{}$EmailParameters.Add('message', $Message)$EmailParameters.Add('saveToSentItems', $true)$EmailParameters.Add('isDeliveryReceiptRequested', $true)Write-Output ""Write-Output "Sending email..."Write-Output ""# Send the messageTry {Send-MgUserMail -UserId $MsgFrom -BodyParameter $EmailParameters -ErrorAction StopWrite-Output ("Shared Mailboxes without MDO2 license report emailed to {0}" -f $ToRecipient.emailAddress.address)} Catch {Write-Output "Unable to send email"Write-Output $_.Exception.Message}Write-Output "All done"
Parameters
ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.-AppId""Application (client) ID for the app registration used to connect.-LookbackDays10How many days back to search for newly created mailboxes or recent activity.-DestinationEmailAddress""Email address that receives the generated report.Attribution
Author
Office365itpros