How to work with soft-deleted objects in Exchange Online

Exchange Online has long supported the concept of soft-deleted (and/or “disconnected”) mailboxes, which was later extended to the inactive mailboxes functionality. Recently, some updates have been made to Exchange Online PowerShell cmdlets, some of which now support parameters specific to soft-deleted objects. So in this article, I’ll try to cover those cmdlets.

Let’s start with soft-deleted mailboxes. But wait, what is a soft-deleted mailbox? Here’s Microsoft’s definition:

A soft-deleted user mailbox is a mailbox that has been deleted using the Microsoft 365 admin center or the Remove-Mailbox cmdlet in Exchange Online PowerShell, and has still been in the Azure Active Directory (Azure AD) recycle bin for less than 30 days.

Inactive mailboxes in turn are soft-deleted mailboxes that are put on hold, thus kept for the duration of the hold. There are some additional details you can read about in the official documentation, but probably the most important thing to note here is that removing the licenses DOES NOT put the mailbox in a soft-deleted state. This is a different operation altogether and puts the mailbox in a disconnected state (again, different from soft-deleted). Amongst other inconveniences, this will render the mailbox transparent to eDiscovery/Content search operations, so use it with care!

Now that we have some understanding of what is a soft-deleted mailbox, how do we go about reporting on them? In most cases, this is just a matter of using the corresponding parameter/switch of the relevant cmdlet. For example, the Get-Mailbox cmdlet has the –SoftDeletedMailbox switch, and if you invoke the cmdlet with it only mailboxes that are in the soft-deleted state will be returned. As mentioned above, inactive mailboxes are technically still counted as soft-deleted ones, even if the 30 days recycle bin retention period has lapsed, as long as they are under the effect of a hold.

Of course, there are more object types than just mailboxes in Exchange Online, and you might also want to report on various relationships between them. Thus the Get-Mailbox cmdlet is not sufficient, and we need a proper list of all cmdlets that support working with soft-deleted mailboxes. To generate such list, we can use few methods. We can of course use PowerShell’s own Get-Command cmdlet and filter out based on the parameter name. The result will resemble the following:

Get-Command -ParameterName *softDeleted* | sort Name

CommandType Name Version Source
----------- ---- ------- ------
Function Get-DistributionGroupMember 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-DynamicDistributionGroupMember 1.0 tmpEXO_ilpc2pqy.g0p
Cmdlet Get-EXOMailbox 2.0.6 ExchangeOnlineManagement
Cmdlet Get-EXOMailboxFolderStatistics 2.0.6 ExchangeOnlineManagement
Cmdlet Get-EXOMailboxPermission 2.0.6 ExchangeOnlineManagement
Cmdlet Get-EXOMailboxStatistics 2.0.6 ExchangeOnlineManagement
Cmdlet Get-EXORecipient 2.0.6 ExchangeOnlineManagement
Function Get-Mailbox 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-MailboxFolderStatistics 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-MailboxPermission 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-MailboxStatistics 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-MailUser 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-Recipient 1.0 tmpEXO_ilpc2pqy.g0p
Function Get-UnifiedGroup 1.0 tmpEXO_ilpc2pqy.g0p
Function Remove-MailboxPermission 1.0 tmpEXO_ilpc2pqy.g0p
Function Test-MailboxAssistant 1.0 tmpEXO_ilpc2pqy.g0p
Function Undo-SoftDeletedMailbox 1.0 tmpEXO_ilpc2pqy.g0p

While this is an easy method to use, you need to remember that Exchange Online’s RBAC model dynamically generates and exports a list of cmdlets the current user has been granted access to, so the list above might be missing some entries. In this specific case, I’ve assigned myself to all the relevant management roles, so the list happens to be an exhaustive one. But here’s how to list the cmdlets based on their definition within Exchange Online:

Get-ManagementRoleEntry "*\*" -Parameters *SoftDeleted* | select -ExpandProperty Name -Unique | sort

Get-DistributionGroupMember
Get-DynamicDistributionGroupMember
Get-Mailbox
Get-MailboxFolderStatistics
Get-MailboxPermission
Get-MailboxStatistics
Get-MailUser
Get-MRSRequest
Get-Recipient
Get-UnifiedGroup
Remove-MailboxPermission
Test-MailboxAssistant
Undo-SoftDeletedMailbox
Undo-SoftDeletedUnifiedGroup

Comparing the two lists, you might see some differences. For example, the Undo-SoftDeletedUnifiedGroup and Get-MRSRequest cmdlets are missing from the first one, whereas any of the REST-based (Get-EXO*) cmdlets are missing from the second one. Without going into more details, the idea here is that it’s best to check both the client- and server-side.

Now that we have our list of cmdlets that support Exchange Online soft-deleted objects, let’s go over each of the entries and add some details and examples!

  • Get-Mailbox – Use the cmdlet along with the –SoftDeletedMailbox switch to return soft-deleted mailbox objects. Do note that the output will only contain soft-deleted mailboxes, thus if you want the full picture with both “regular” and soft-deleted mailboxes you’d need to run it twice – once with the switch and once without. Also note that Inactive mailboxes will also appear in the output as soft-deleted ones, and if your tenant has an org-wide retention policy to preserve data, any soft-deleted mailbox will immediately be marked as inactive one as well.
    Get-Mailbox -SoftDeletedMailbox | select Name,RecipientTypeDetails,WhenSoftDeleted,IsInactiveMailbox
    
    Name RecipientTypeDetails WhenSoftDeleted IsInactiveMailbox
    ---- -------------------- --------------- -----------------
    huku UserMailbox 21/08/2022 15:15:27 False

    PowerShell example

  • Get-ExOMailbox – pretty much the same as above, just using the new REST-based ExO cmdlets. Since a limited subset of the mailbox properties are returned by default, you might want to explicitly fetch the WhenSoftDeleted and IsInactiveMailbox ones (-Properties parameter).
    Get-EXOMailbox -SoftDeletedMailbox -ResultSize 1 -Properties WhenSoftDeleted,IsInactiveMailbox | select Name,RecipientTypeDetails,WhenSoftDeleted,IsInactiveMailboxName RecipientTypeDetails WhenSoftDeleted IsInactiveMailbox
    ---- -------------------- --------------- -----------------
    aaaaaaaaaa SharedMailbox 25/06/2022 20:22:53 True
  • Get-MailboxPermission and Get-ExOMailboxPermission – both cmdlets support the –SoftDeletedMailbox parameter to report on permissions granted to the soft-deleted mailbox. As described in more detail in a previous article, you might want to also use the –IncludeSoftDeletedUserPermissions and –IncludeUnresolvedPermissions parameters to make the list of permissions as comprehensive as possible.
    Get-MailboxPermission huku -SoftDeletedMailbox -IncludeSoftDeletedUserPermissions -IncludeUnresolvedPermissions
    
    AccessRights : {FullAccess, ReadPermission}
    Deny : False
    InheritanceType : All
    User : NT AUTHORITY\SELF
    UserSid : S-1-5-10
    Identity : Soft Deleted Objects\huku
  • Get-MailboxStatistics and Get-EXOMailboxStatistics – use these cmdlets to get the mailbox statistics for a soft-deleted mailbox. Do note that the parameter you have to use is called –IncludeSoftDeletedRecipients.
    Get-EXOMailboxStatistics aaaaaaaaaa -IncludeSoftDeletedRecipients
    
    DisplayName : aaaaaaaaaa
    MailboxGuid : c7a5178b-637f-4daf-8e02-5eea6b3dc9dd
    DeletedItemCount : 0
    ItemCount : 1
    TotalDeletedItemSize : 0 B (0 bytes)
    TotalItemSize : 6.455 KB (6,610 bytes)
  • Get-MailboxFolderStatistics and Get-ExOMailboxFolderStatistics – as above, if you are looking for folder-level statistics for a soft-deleted mailbox, run the corresponding cmdlet with the –IncludeSoftDeletedRecipients switch.
    Get-EXOMailboxFolderStatistics aaaaaaaaaa -IncludeSoftDeletedRecipients
  • Get-MailUser – use this cmdlet to get a list of soft-deleted mail user objects. The corresponding parameter name is –SoftDeletedMailUser. Interestingly enough, the –IsInactiveMailbox property is set to True for most soft-deleted mail users, even though they never had a mailbox.
    Get-MailUser -SoftDeletedMailUser | select Name,RecipientTypeDetails,WhenSoftDeleted,IsInactiveMailbox,ExternalEmailAddress
    
    Name RecipientTypeDetails WhenSoftDeleted IsInactiveMailbox ExternalEmailAddress
    ---- -------------------- --------------- ----------------- --------------------
    vasil.michev_quest.com#EXT# GuestMailUser 29/12/2021 14:50:26 True SMTP:vasil.michev@quest.com
    vasil.michev_quadrotech-it.com#EXT# GuestMailUser 29/12/2021 14:49:40 True SMTP:vasil.michev@quadrotech-it.com
    Guest_1503bf9b2e7b4720b2ec39edca767037 GuestMailUser 11/03/2022 18:18:03 True SMTP:alexw@m365x223955.onmicrosoft.com
    Guest_92e9a897c78042ec94971b576d0681ed GuestMailUser 09/02/2022 11:00:23 True SMTP:alexw@m365x223955.onmicrosoft.com
  • Get-Recipient and Get-EXORecipient – these cmdlets support the –IncludeSoftDeletedRecipients switch and including it will ensure that any soft-deleted objects are returned in the output. At least that’s the theory. In practice, the –IncludeSoftDeletedRecipients parameter behaves randomly. Sometimes the cmdlet returns the exact same set of results with or without the parameter. Other times it returns some, but not all soft-deleted objects. It’s unreliable at best, which is a shame, given my love for the otherwise very useful Get-Recipient cmdlet. Luckily, we can utilize a workaround to get the desired effect, by specifying the -OrganizationalUnit “Soft Deleted Objects” parameter.
    C:\> Get-Recipient -IncludeSoftDeletedRecipients | select Name,RecipientTypeDetails,WhenSoftDeleted
    
    C:\> Get-Recipient -OrganizationalUnit "Soft Deleted Objects" | select Name,RecipientTypeDetails,WhenSoftDeleted
  • Get-UnifiedGroup – use the -IncludeSoftDeletedGroups parameter. Note that there is no matching Get-ExOUnifiedGroup cmdlet currently.
    Get-UnifiedGroup -IncludeSoftDeletedGroups | select Name,RecipientTypeDetails,WhenSoftDeleted
  • Get-DistributionGroupMember and Get-DynamicDistributionGroupMember – both cmdlets support the –IncludeSoftDeletedObjects parameter, thus allowing you to generate a membership report that incudes soft-deleted objects.
    C:\> Get-DistributionGroupMember DG -IncludeSoftDeletedObjects | select Name,RecipientTypeDetails,WhenSoftDeleted
    
    Name RecipientTypeDetails WhenSoftDeleted
    ---- -------------------- ---------------
    vasil UserMailbox
    empty MailUniversalDistributionGroup
    tempxxx_abv.bg#EXT# GuestMailUser
    vasil.michev_quadrotech-it.com#EXT# GuestMailUser 29/12/2021 14:49:40
    marian_ski_outlook.com#EXT# UserMailbox 14/11/2019 09:31:10
    
    C:\> Get-DynamicDistributionGroupMember GuestUsers -IncludeSoftDeletedObjects | select Name,RecipientTypeDetails,WhenSoftDeleted
    
    Name RecipientTypeDetails WhenSoftDeleted
    ---- -------------------- ---------------
    michev_gmail.com#EXT# GuestMailUser
    tempxxx_abv.bg#EXT# GuestMailUser
    vasil.michev_quadrotech-it.com#EXT# GuestMailUser 29/12/2021 14:49:40

This concludes the list of Get- cmdlets that support soft-deleted objects. Apart from the Get- cmdlets, few other cmdlets also support such parameters and can be used to perform various actions against them. The prime example here would be the Undo-SoftDeletedMailbox and Undo-SoftDeletedUnifiedGroup cmdlets, which can be used to recover soft-deleted mailboxes and M365 Groups, respectively. No cmdlet exists within Exchange Online to recover MailUser objects (including Guests), instead you can use the good old MSOnline, Azure AD PowerShell or MG Graph SDK cmdlets.

The last cmdlet we want to cover is the Remove-MailboxPermission. Using the –SoftDeletedMailbox parameter allows you to run the cmdlet to clear permission entries on a soft-deleted mailbox. The Test-MailboxAssistant cmdlet also shows as having  support for -SoftDeletedMailbox parameter, however the cmdlet itself is not usable. Lastly, Get-MRSRequest is also a cmdlet that currently cannot be used.

And with that, we’ve covered all Exchange Online cmdlets that currently support soft-deleted objects. While there is no universal support for soft-deleted objects and even some of the cmdlets that do support them behave unreliably, it’s still useful to be able to report on such objects. And keep in mind that even if a given cmdlet does not support a “soft-deleted” parameter, there might be other ways to get the same data, such as utilizing PowerShell cmdlets from other modules, or direct Graph API queries. Or utilizing workarounds within Exchange Online itself, such as the –OrganizationalUnit parameter.

For example, even though the Get-User cmdlet does not support a “soft-deleted” parameter, one can do the following:

Get-User -OrganizationalUnit "Soft Deleted Objects" | select Name,RecipientTypeDetails,WhenSoftDeleted,IsInactiveMailbox

Name RecipientTypeDetails WhenSoftDeleted IsInactiveMailbox
---- -------------------- --------------- -----------------
ToBeRemoved SharedMailbox 02/11/2021 18:24:37 True
SchedAppPermissions_04bfa1c22f SchedulingMailbox 17/03/2022 17:44:56 True
inactive UserMailbox 08/05/2018 16:25:33 True
Guest_92e9a897c78042ec94971b576d0681ed GuestMailUser 09/02/2022 11:00:23 True
Tony.Redmond_redmondassociates.org#EXT# GuestMailUser 02/11/2020 16:45:28 False

We used a similar workaround for the Get-Recipient cmdlet above. Interestingly enough, other cmdlets that support this workaround include the Get-Group one, although as expected its output will only include soft-deleted M365 Group objects.

UPDATE: I believe I figured out what the oddity with Get-Recipient is. And as a bonus, I figured out how to list all “inactive” M365 Group objects. Turns out, for M365 Group objects, the rule that an inactive object is always considered a soft-deleted one as does not apply. At least, not when you run the Get-Recipient cmdlet with the –IncludeSoftDeletedRecipients switch. Thus, the output will not include inactive M365 Group objects. However, when you run the “workaround” with -OrganizationalUnit “Soft Deleted Objects”, inactive M365 Groups are returned. Here’s an illustration:

PowerShell example for working with soft-deleted objectsSo, 20 out of the 22 M365 Group objects found under the soft-deleted container have their ExternalDirectoryObjectId null-ed, which indicates they are now considered “inactive” ones (there is no “IsInactiveGroup” or similar property). Those objects will not be returned when running Get-Recipient with the –IncludeSoftDeletedRecipients switch. Incidentally, 20 are the “missing” objects when you compare the counts above. Hence, we can use the following cmdlet to list all inactive M365 Groups within the organization:

Get-Recipient -OrganizationalUnit "Soft Deleted Objects" -RecipientTypeDetails "GroupMailbox" | ? {!$_.ExternalDirectoryObjectId} | select Name,WhenSoftDeleted

UPDATE: Just to add two things. First, both soft-deleted and inactive mailboxes are still considered a valid security principal, as evident by the fact they still have permission entries assigned. Second, you can get info on any valid soft-deleted Security principal object via the Get-SecurityPrincipal, as long as you use the OU workaround:

Get-SecurityPrincipal inactive -OrganizationalUnit "Soft Deleted Objects"

1 thought on “How to work with soft-deleted objects in Exchange Online

  1. Martin says:

    By default most of these commands return a limited number of objects and need to be used with the “ResultSize” parameter 🙂

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

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