In the note I published on Practical365.com, I included a PowerShell script to report the status of archive-enabled mailboxes. Afterwards, I was asked whether it would be easy to adapt the script to report mailboxes which might be in danger of approaching the new 1.5 TB limit.
Good idea, I thought, and set to work. The full script is downloadable from GitHub, and here’s the flow of the processing.
Declare variables to hold the number of bytes in 1.5 TB (1649267441664) and the warning level. I selected 90% as a good warning threshold. You could select a lower or higher value.
Find the mailboxes with archives. This is a server-side filter with Get-ExoMailbox, so it’s reasonably fast. I then use a client-side filter to remove mailboxes which don’t use expandable archives.
Calculate the mailbox size. In this instance, Microsoft is taking an all-up approach and will assess the 1.5 TB limit against the complete mailbox contents, including Recoverable Items. This is unlike normal mailbox storage quotas, which only count “non-dumpster” folders.
Check if each mailbox is within the warning limit and create a status message if true.
I wanted some way to assess of the daily growth rate for the archive. There’s no obvious way to generate this figure from PowerShell, so I use the creation date for the mailbox to calculate the number of days in use. I then divide the number of days into the current archive size to calculate the average daily growth. It’s a crude mechanism but better than nothing.
I also use the average daily growth to estimate the number of days until the archive hits the limit. For most mailboxes, this is a big number.
Here’s the main processing loop for the mailboxes:
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($M in $ExMbx) {
$Status = $Null
Write-Host "Processing mailbox" $M.DisplayName
[int]$DaysSinceCreation = ((New-TimeSpan -Start ($M.WhenCreated) -End ($Now)).Days)
$Stats = Get-ExoMailboxStatistics -Archive -Identity $M.UserPrincipalName
[string]$ArchiveSize = $Stats.TotalItemSize.Value
[string]$DeletedArchiveItems = $Stats.TotalDeletedItemSize.Value
[long]$BytesInArchive = $Stats.TotalItemSize.Value.ToBytes()
[long]$BytesInRecoverableItems = $Stats.TotalDeletedItemSize.Value.ToBytes()
[long]$TotalBytesInArchive = $BytesInArchive + $BytesInRecoverableItems
# Check if archive size is within 10% of the 1.5 TB limit - the size that counts is the combination of Recoverable Items and normal folders
If ($TotalBytesInArchive -ge $TBBytesWarning)
{ Write-Host ("Archive size {0} for {1} is within 10% of 1.5 TB limit" -f $ArchiveSize, $M.DisplayName )
$Status = "Archive within 10% of 1.5 TB limit" }
[long]$BytesPerDay = $TotalBytesInArchive/$DaysSinceCreation
[long]$NumberDaysLeft = (($TBBytes - $TotalBytesInArchive)/$BytesPerDay)
$BytesPerDayMB = $BytesPerDay/1MB
$GrowthRateDay = [math]::Round($BytesPerDayMB,4)
$TotalArchiveSizeGB = [math]::Round(($TotalBytesInArchive/1GB),2)
$ReportLine = [PSCustomObject][Ordered]@{
Mailbox = $M.DisplayName
UPN = $M.UserPrincipalName
Created = $M.WhenCreated
Days = $DaysSinceCreation
Type = $M.RecipientTypeDetails
"Archive Quota" = $M.ArchiveQuota.Split("(")[0]
"Archive Status" = $M.ArchiveStatus
"Archive Size" = $ArchiveSize.Split("(")[0]
"Archive Items" = $Stats.ItemCount
"Deleted Archive Items Size" = $DeletedArchiveItems.Split("(")[0]
"Deleted Items" = $Stats.DeletedItemCount
"Total Archive Size (GB)" = $TotalArchiveSizeGB
"Daily Growth Rate (MB)" = $GrowthRateDay
"Days Left to Limit" = $NumberDaysLeft
Status = $Status
}
$Report.Add($ReportLine)
} #End ForEach
Considering the Data
The script generates a CSV file containing the mailbox data. I also like to output the data on screen using the Out-GridView cmdlet to get some insight into the results. For example, Figure 1 shows some output from mailboxes in my tenant. As you can see, at a 18.07 MB/day growth rate, it will take my archive 84,228 days to get from its current 9.129 GB to 1.5 TB. What a relief!
Figure 1: Some archive mailboxes will take a long time to reach the 1.5 TB limit
Example of PowerShell Flexibility
The script works as an example of how PowerShell delivers insight for Microsoft 365 tenant administrators, which is why every tenant administrator should be familiar with PowerShell and be able to run scripts and make simple code changes. Because most archives are less than 100 GB and won’t get near the new 1.5 TB limit in their lifetime, I suspect that few tenants will find the script valuable in an operational sense. However, it’s always nice to be able to answer questions with a few lines of code.
Learn more about how Office 365 really works (including PowerShell and archive mailboxes) on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.
8 Replies to “How to Find Exchange Online Archive Mailboxes Close to the New 1.5 TB Limit”
Thanks for sharing!
I tried the script right out of the box and it threw an error:
Get-OrganizationConfig : The term ‘Get-OrganizationConfig’ is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct a
nd try again.
At C:\Temp2\ReportAutoExpandingArchives.PS1:7 char:7
+ If (((Get-OrganizationConfig).AutoExpandingArchiveEnabled) -ne $True) …
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-OrganizationConfig:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-ExoMailbox : No valid token was found in the cache, please run Connect-ExchangeOnline.
At C:\Temp2\ReportAutoExpandingArchives.PS1:11 char:15
+ … rray]$Mbx = Get-ExoMailbox -RecipientTypeDetails SharedMailbox, UserM …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ProtocolError: ) [Get-EXOMailbox], AuthenticationException
+ FullyQualifiedErrorId : No valid token was found in the cache, please run Connect-ExchangeOnline.,Microsoft.Exch
ange.Management.RestApiClient.GetExoMailbox
You need to connect to Exchange Online. I added this line to the script in GitHub:
$Modules = Get-Module
If (“ExchangeOnlineManagement” -notin $Modules.Name) {Write-Host “Please connect to Exchange Online Management before continuing…”;break}
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
Thanks for sharing!
I tried the script right out of the box and it threw an error:
Get-OrganizationConfig : The term ‘Get-OrganizationConfig’ is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct a
nd try again.
At C:\Temp2\ReportAutoExpandingArchives.PS1:7 char:7
+ If (((Get-OrganizationConfig).AutoExpandingArchiveEnabled) -ne $True) …
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-OrganizationConfig:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-ExoMailbox : No valid token was found in the cache, please run Connect-ExchangeOnline.
At C:\Temp2\ReportAutoExpandingArchives.PS1:11 char:15
+ … rray]$Mbx = Get-ExoMailbox -RecipientTypeDetails SharedMailbox, UserM …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ProtocolError: ) [Get-EXOMailbox], AuthenticationException
+ FullyQualifiedErrorId : No valid token was found in the cache, please run Connect-ExchangeOnline.,Microsoft.Exch
ange.Management.RestApiClient.GetExoMailbox
You need to connect to Exchange Online. I added this line to the script in GitHub:
$Modules = Get-Module
If (“ExchangeOnlineManagement” -notin $Modules.Name) {Write-Host “Please connect to Exchange Online Management before continuing…”;break}
when trying to run via ISE, I get told “Expanding archives are not enabled in this tenant” – they most definitely are though!
Work as intended!
Tx a lot for sharing this script
thank you worked like a charm!!