As I was making some changes to the Mailbox permissions inventory script, I noticed few new parameters made available for the Get-MailboxPermission cmdlet. So it was only natural to take them for a spin.
The parameters in question include -IncludeUnresolvedPermissions and -IncludeSoftDeletedUserPermissions, as well as the generic -SoftDeletedMailbox. Here are their corresponding descriptions from the online help document:
- IncludeSoftDeletedUserPermissions – returns permissions from soft-deleted mailbox users in the results. In other words, if you have granted access to a given user, and then soft-deleted his account, you can use the –IncludeSoftDeletedUserPermissions switch to return such entries in the Get-MailboxPermission cmdlet output. If you do not specify the switch, entries corresponding to soft-deleted mailboxes will be omitted.
- IncludeUnresolvedPermissions – returns unresolved permissions in the results. Those correspond to entries that no longer exist in the directory, aka orphaned entries.
- SoftDeletedMailbox – is required to return soft-deleted mailboxes in the results. This also includes any inactive mailboxes. Use the switch when you want to include soft-deleted/inactive mailboxes in your report, without it a “object not found” error will be thrown.
Since an example is worth a thousand words, here’s how the aforementioned parameters can be used. Let’s say we have a mailbox called “shared”, and we’ve granted few people Full access permissions over it. Here’s what the Get-MailboxPermission output looks like, with the NT AUTHORITY\SELF entries removed for brevity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | C:\> Get-MailboxPermission shared AccessRights : {FullAccess} Deny : False InheritanceType : All User : vasil @michevdev3 .onmicrosoft.com UserSid : S-1-5-21-4288531086-171750275-1771573367-6121987 Identity : shared IsInherited : False IsValid : True ObjectState : Unchanged AccessRights : {FullAccess} Deny : False InheritanceType : All User : huku @pta .michev.info UserSid : S-1-5-21-4288531086-171750275-1771573367-8593717 Identity : shared IsInherited : False IsValid : True ObjectState : Unchanged |
Let’s say we now remove the huku@pta.michev.info user, putting it into a soft-deleted state. What happens with the permissions? If we run the Get-MailboxPermission cmdlet again, we will notice that the entry is missing. If we specify the -IncludeSoftDeletedUserPermissions parameter as well however, we will see the entry is still present, as illustrated on the screenshot below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | C:\> Remove-Mailbox huku @pta .michev.info Confirm Are you sure you want to perform this action? Removing the mailbox Identity: "huku@pta.michev.info" will mark the mailbox and the archive, if present, for deletion. The associated Windows Live ID "huku@pta.michev.info" will also be deleted and will not be available for any other Windows Live service. [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help ( default is "Y" ): C:\> Get-MailboxPermission shared -User huku @pta .michev.info Write-ErrorMessage : |Microsoft .Exchange.Configuration.Tasks.ThrowTerminatingErrorException |User or group "huku@pta.michev.info" wasn 't found. Please make sure you' ve typed it correctly. At D:\Temp\tmpEXO_25s4ai4l.ge4\tmpEXO_25s4ai4l.ge4.psm1:1109 char:13 + Write-ErrorMessage $ErrorObject $IsFromBatchingRequest + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [ Get-MailboxPermission ], ThrowTerminatingErrorException + FullyQualifiedErrorId : [Server=AS8P190MB1367,RequestId=b0aaf82d-bca1-3461-c8a5-00e325786583,TimeStamp=Sun, 21 Aug 2022 12:15:38 GMT], Write-ErrorMessage C:\> Get-MailboxPermission shared -User huku @pta .michev.info -IncludeSoftDeletedUserPermissions AccessRights : {FullAccess} Deny : False InheritanceType : All User : huku @pta .michev.info UserSid : S-1-5-21-4288531086-171750275-1771573367-8593717 Identity : shared IsInherited : False IsValid : True ObjectState : Unchanged |
And this is what the –IncludeSoftDeletedUserPermissions parameter is used for, in a nutshell. If at some point later you recover the soft-deleted mailbox, the permission entry will auto-appear in the “regular” Get-MailboxPermission output, and you no longer need to specify the switch. The –IncludeUnresolvedPermissions switch works in a similar fashion, but for “orphaned” entries. The biggest difference between the two is that you cannot “recover” orphaned entries.
Lastly, let’s also showcase how the -SoftDeletedMailbox switch works. Basically, you use it to force the Get-MailboxPermission cmdlet to return output for soft-deleted (and/or inactive) mailboxes. Without the parameter, an error will be thrown. With it, you can expect the regular output to appear:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | C:\> Get-MailboxPermission huku @pta .michev.info Write-ErrorMessage : ExE610C8 |Microsoft .Exchange.Configuration.Tasks.ManagementObjectNotFoundException |Couldn 't find ' huku @pta .michev.info' as a recipient. At D:\Temp\tmpEXO_25s4ai4l.ge4\tmpEXO_25s4ai4l.ge4.psm1:1109 char:13 + Write-ErrorMessage $ErrorObject $IsFromBatchingRequest + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [ Get-MailboxPermission ], ManagementObjectNotFoundException + FullyQualifiedErrorId : [Server=AS8P190MB1367,RequestId=f61b110c-e9c0-e33d-3004-633e2ea6fdc2,TimeStamp=Sun, 21 Aug 2022 12:26:28 GMT], Write-ErrorMessage C:\> Get-MailboxPermission huku @pta .michev.info -SoftDeletedMailbox AccessRights : {FullAccess, ReadPermission} Deny : False InheritanceType : All User : NT AUTHORITY\SELF UserSid : S-1-5-10 Identity : Soft Deleted Objects\huku IsInherited : False IsValid : True ObjectState : Unchanged |
An interesting thing to note in the output is that the identity of the soft-deleted object is prefixed with “Soft Deleted Objects”, which is the name of the Organizational Unit where such objects are stored. On the other hand, the User property value returned for permissions granted to soft-deleted mailboxes does not include the prefix, which makes it a bit harder to handle.
Speaking about the output, you might also note that the UserSid property is now returned. Unfortunately, the Get-Mailbox cmdlet does not resolve SID values, and while you can use the Get-User cmdlet instead, this one does not support the -SoftDeletedMailbox switch (whereas Get-Mailbox does). But, there is a workaround you can use here too – specify the –OrganizationalUnit parameter with value of “Soft Deleted Objects” and voila:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | C:\> Get-User S-1-5-21-4288531086-171750275-1771573367-8593717 Write-ErrorMessage : Ex6F9304 |Microsoft .Exchange.Configuration.Tasks.ManagementObjectNotFoundException |The operation couldn 't be performed because object ' S-1-5-21-4288531086-171750275-1771573367-8593717 ' couldn' t be found on 'DBBPR01A07DC006.EURPR01A007.PROD.OUTLOOK.COM' . At D:\Temp\tmpEXO_25s4ai4l.ge4\tmpEXO_25s4ai4l.ge4.psm1:1109 char:13 + Write-ErrorMessage $ErrorObject $IsFromBatchingRequest + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [ get-User ], ManagementObjectNotFoundException + FullyQualifiedErrorId : [Server=AS8P190MB1367,RequestId=2e0567ad-347e-895a-8ffe-da3f86c92d32,TimeStamp=Sun, 21 Aug 2022 12:34:45 GMT], Write-ErrorMessage C:\> Get-User S-1-5-21-4288531086-171750275-1771573367-8593717 -OrganizationalUnit "Soft Deleted Objects" IsSecurityPrincipal : True SamAccountName : huku57943-1091673623 Sid : S-1-5-21-4288531086-171750275-1771573367-8593717 SidHistory : {} UserPrincipalName : huku @pta .michev.info ... |
And while we’re discussing working/non-working parameters, it looks like the -Gr0upMailbox switch of the Get-MailboxPermission cmdlet cannot be used against any Unified group identifier. Which is fine I suppose, as we still don’t have a way of granting mailbox-level permissions on Group mailbox objects.
One more thing – we can now grant permissions to service principal objects too! To do this, you first need to “copy” the service principal object and create a representation of it within ExODS. Don’t ask me why Microsoft isn’t doing this automatically, it is what it is. Anyway, to create an (ExO) Service principal, use the New-ServicePrincipal cmdlet and provide values for the –AppId (clientID) and –ServiceId (objectId) parameters, and optional –DisplayName. For example:
1 | New-ServicePrincipal -AppId ae23ad05-xxxx-xxxx-xxxx-78b7a0757f5f -ServiceId 2a63aee1-xxxx-xxxx-xxxx-d40971066292 -DisplayName "Service Principal for ExOPS app" |
Interestingly enough, NO validation is made for the values you provide, so you can create something at random. Which makes it that more important to carefully fetch the real values from either the Azure AD UI, PowerShell or the Graph API!
Once the Service principal object has been created, you can use it to delegate permissions. To obtain a list of service principal objects, use the Get-ServicePrincipal cmdlet. Even though a new value for RecipientTypeDetails seems to have been added, ServicePrinciple (note the different spelling!), it’s not currently possible to query service principal objects via Get-Recipient or any other cmdlet, only the Get-ServicePrincipal works. Anyway, to grant permissions, use the familiar syntax:
1 2 3 4 | Add-MailboxPermission sharednew -User 2a63aee1-db17-489d-a8ab-d40971066292 -AccessRights FullAccess -AutoMapping $false -------- ---- ------------ ----------- ---- sharednew EURPR03A001\ $K0NE ... {FullAccess} False False |
And you can of course query the permissions:
1 2 3 4 5 6 7 8 9 10 11 12 | Get-MailboxPermission sharednew -User 2a63aee1-db17-489d-a8ab-d40971066292 | fl * -Force PSComputerName : outlook.office365.com PSShowComputerName : False AccessRights : {FullAccess} Deny : False InheritanceType : All User : 2a63aee1-db17-489d-a8ab-d40971066292 UserSid : S-1-5-21-3675944716-2045640655-299186705-56056852 IsInherited : False IsValid : True ObjectState : Unchanged |
Only Full mailbox permissions seem to be supported at this point, you cannot delegate folder-level access to a service principal object.
Lastly, it’s worth mentioning that we can still use the –ReadFromDomainController parameter to force the full mailbox object to be returned. Unfortunately, this only works for the mailbox for which we’re querying the permissions, but still it’s a valuable way to peek behind the curtain of the Exchange Online directory.
1 thought on “Improved handling of Mailbox permissions in Exchange Online”