After publishing our article and script on getting the mailbox folder permissions inventory, few folks have reached out to ask whether it’s possible to have a script that sets the permissions instead of just reporting on them. This is also a common ask for organizations that use folder-level permissions instead of Full access for sharing mailbox data, for example companies that have previously used Lotus Notes. Granting folder level permissions is also needed in situations where you want to share the items but want to prevent users from editing or deleting them. So how do we go about this?
In this scenario, we are interested in granting permissions on all folders found in particular mailbox. If you only want this for specific folder the Add-MailboxFolderPermission cmdlet already takes care of that. The script of course still makes use of this cmdlet, so in order to configure the permissions we need to know few pieces of information: the folder identity, the user to which to grant the permissions and the permission level. Instead of requiring you to provide a list of all the folder identities for a particular mailbox however, the script simplifies the task by only requiring the corresponding mailbox identity.
Of course, we don’t really need *all* folders in the mailbox, as some of those are not accessible via Outlook or any other client, thus granting permissions on them doesn’t make sense. Instead, what we are interested in is a set of default folders plus any custom-created ones. To generate the list of folders, the script uses the ReturnFolderList helper function, which only takes a single parameter, the SMTP address of the mailbox. This is basically a version of the function we used in our “mailbox folder permission inventory” script, stripped down of all the output elements, error checks and other fluff.
Outside of the helper function, two array variables are introduced in order to help us build the list of folders: the $includedfolders variable lists the folder TYPEs we are interested in, such as Inbox or SentItems, while the $excludedfolders variable helps us get rid of any folders we don’t want to touch. Such examples are any folders that are not marked as default but are still not accessible in the clients, or folders like “Quick Steps Settings”. Feel free to make any changes to those variables as you see fit. Note that the $excludedfolders array lists the folder NAMES, so make sure to account for any language-specific values.
Once the list of folders is generated, the actual permission stamping is done via the Set-MailboxFolderPermissionsRecursive function, which is the bulk of the script. The function has the following parameters:
- Mailbox: used to designate the mailbox on which permissions will be granted. Any valid Exchange mailbox identifier can be specified. Multiple delegates can be specified in a comma-separated list or array. You can also use the Identity parameter as alias.
- User: used to designate the user to which permissions will be granted. Any valid Exchange security principal can be specified, including Security groups. Multiple delegates can be specified in a comma-separated list or array. You can also use the Delegate parameter as alias.
- AccessRights: used to specify the permission level to be granted. Any valid folder-level permission can be specified. Roles have precedence over individual permissions entries. For more details read here: https://docs.microsoft.com/en-us/powershell/module/exchange/mailboxes/Add-MailboxFolderPermission?view=exchange-ps
- WhatIf: used to run the script in a “simulation” mode, without making any actual changes. Works the same way as with other Exchange cmdlets.
- Verbose: used to force the script to provide additional details on the cmdlet progress. Useful when troubleshooting issues.
- Quiet: used to suppress output to the console. By default, each added/changed permission entry will be displayed in the console, apart from saving it to the CSV file.
The same set of parameters is used by the script as a whole, any values provided are then fed to the function thanks to the splatting feature. The first three parameters, namely Mailbox, User and AccessRights are mandatory. None of the parameters features pipeline support, that’s a deliberate design decision. You can however provide multiple values, see the examples below or the cmdlet help.
Before turning to actual examples, here’s the download link for the script: https://github.com/michevnew/PowerShell/blob/master/Set_Folder_Permissions_recursive_BULK.ps1
Now, here are some example uses of the script. First, a simple one where you are granting Owner level permissions for user Vasil on all folders in a shared mailbox:
.\Set_Folder_Permissions_recursive_BULK.ps1 -Mailbox sharednew -User vasil -AccessRights Owner
A more complicated example where user John is added a set of individual permissions entries (CreateItems and DeleteOwnedItems) to all folders in several mailboxes. The same AccessRights permission level will be configured on all folders in all mailboxes for all delegates, so make sure you provide just the right set of parameters! In an existing permission entry for the same User is detected, it will be updated to match the newly provided value.
.\Set_Folder_Permissions_recursive_BULK.ps1 -Mailbox shared1,shared2 -User firstname.lastname@example.org -AccessRights CreateItems,DeleteOwnedItems
If you want to get really wild with the script, you can provide lists/arrays of objects instead. In this example, we will pass the list of all Shared mailboxes in the organization. Be careful though, as with great power comes great responsibility. While there are multiple checks performed on the validity and uniqueness of the parameter values, you might want to consider running the script in “test” mode using both the –WhatIf and –Verbose parameters in order to “see” what changes it will execute.
.\Set_Folder_Permissions_recursive_BULK.ps1 -Mailbox (Get-Mailbox -RecipientTypeDetails SharedMailbox) -User delegate1,delegate2 -AccessRights Author -WhatIf -Verbose
Output of the script will by default be written to the console as well as to a CSV file in the working directory, so that you can easily review the changes that were made. If you use the –Quiet switch, only the CSV file will be generated. If you want to prevent the creation of the CSV file as well, comment line 196 of the script. Output will also be stored in the global variable $varFolderPermissions for reuse. Below is an example on how the output file will look like:
Some additional notes on the script. It should run OK against both Exchange Online and Exchange Server, including the EMS, however it requires at minimum PowerShell v3. No connectivity logic is included, it’s assumed that you are running it from a console with Exchange Remote PowerShell session already established. If no such session is detected, the script will exit. The script has not been extensively tested against older Exchange versions, so let me know if you run into any issues with those.
As customary, we’ve tried to follow the best practices when it comes to executing cmdlets against large number of objects. Invoke-Command is used where possible in order to minimize the amount of data returned and the script execution time. A simple form of throttling prevention is also used by adding artificial delay on line 152, feel free to edit it as needed. For a more robust solution, consider wrapping the whole script via the “Robust Cloud Command” method as detailed here.
Another thing worth mentioning is that the –Confirm switch is not used. This follow the behavior or the built-in Exchange cmdlets, where only “destructive” actions need to be confirmed. Also, the script does not support setting the FreeBusyTimeAndSubjectAndLocation and FreeBusyTimeOnly permissions, as those are valid for only Calendar folders. Similarly, the –SharingPermissionFlags parameter for Add/Set-MailboxFolderPermission is not used.