A script to bulk-modify permissions on Public Folders

I’m still working on clearing up an enormous number of public folders prior to migration to Exchange 2010 (from 2007).

The permissions structure was not well managed so I have been applying a set of standard groups (Read, Update and Change) to each PF, and at the same time removing any rights granted to Everyone and ANONYMOUS LOGON, and tidying up ACLs left over from deleted accounts.

PF permissions are difficult to fix because they are applied directly to each group. When a PF is created it inherits the rights of its parent, but after that its ACL is individually managed. You can’t just change a permission at the top and expect it to filter down.

Another thing to note about PF permissions is that they are cumulative and there is no deny. The only way to prevent someone seeing a PF is to not give them any rights in the first place.

The final point to note is that deleted accounts don’t seem to get cleared out of the ACL automatically, so by far the best practise is to use groups. Here I have previously created a set of permissions groups for each major folder tree, with their names denoted by the $pfgroupstub that is passed to the script..

To run the script I call it like so (the double-quoting is needed if there are spaces in the folder names):

./fix-pfacl.ps1 -pfroot "'/Top Folder/sub-folder'" -pfgroupstub 'PF_subfolder'

This would have the effect of setting the permissions like this:

\Everyone None
NT AUTHORITY\ANONYMOUS LOGON None
MYDOMAIN\PF_subfolder_Read Reviewer
MYDOMAIN\PF_subfolder_Update Author
MYDOMAIN\PF_subfolder_Change Publishing Editor
MYDOMAIN\PF_ALL_Read Reviewer
MYDOMAIN\PF_ALL_Update Author
MYDOMAIN\PF_ALL_Change Publishing Editor

Note: Any other explicit rights that were already applied will not be affected.

The Script

PARAM([string]$pfroot,[string]$pfgroupstub)

[string]$pfserver = 'MyServer'

[string]$read_group = $pfgroupstub + '_Read'
[string]$update_group = $pfgroupstub + '_Update'
[string]$change_group = $pfgroupstub + '_Change'

[boolean]$stdok = $false

function fixacl([string]$pfname) {

  $pfacl = get-publicfolderclientpermission -server $pfserver -identity $pfname

  write-host $pfname

  foreach ($acl in $pfacl){
    if ($acl.User.IsAnonymous -eq $true -and $acl.AccessRights[0].Permission -ne 'None'){
      remove-publicfolderclientpermission -server $pfserver -identity $pfname -user $acl.User -AccessRights $acl.AccessRights -Confirm:$false -erroraction silentlycontinue
      write-host "Removed ANONYMOUS"
    }
    if ($acl.User.IsDefault -eq $true -and $acl.AccessRights[0].Permission -ne 'None'){
      remove-publicfolderclientpermission -server $pfserver -identity $pfname -user $acl.User -AccessRights $acl.AccessRights -Confirm:$false -erroraction silentlycontinue
      write-host "Removed Everyone"
    }
    if (($acl.User.ExchangeAddressBookDisplayName -ne $null) -and ($acl.User.ExchangeAddressBookDisplayName.StartsWith('NT User:S-1-5'))){
      remove-publicfolderclientpermission -server $pfserver -identity $pfname -user $acl.User -AccessRights $acl.AccessRights -Confirm:$false -erroraction silentlycontinue
      write-host "Removed deleted"
    }
    if (($acl.User.ExchangeAddressBookDisplayName -ne $null) -and ($acl.User.ExchangeAddressBookDisplayName.Contains($pfgroupstub))){
      $stdok = $true
    }
  }

  if ($stdok -eq $false){
    write-host "Adding default groups"

    add-publicfolderclientpermission -server $pfserver -identity $pfname -user $read_group -AccessRights Reviewer -Confirm:$false -erroraction silentlycontinue
    add-publicfolderclientpermission -server $pfserver -identity $pfname -user $update_group -AccessRights Author -Confirm:$false -erroraction silentlycontinue
    add-publicfolderclientpermission -server $pfserver -identity $pfname -user $change_group -AccessRights PublishingEditor -Confirm:$false -erroraction silentlycontinue

    add-publicfolderclientpermission -server $pfserver -identity $pfname -user 'PF_ALL_Read' -AccessRights Reviewer -Confirm:$false -erroraction silentlycontinue
    add-publicfolderclientpermission -server $pfserver -identity $pfname -user 'PF_ALL_Update' -AccessRights Author -Confirm:$false -erroraction silentlycontinue
    add-publicfolderclientpermission -server $pfserver -identity $pfname -user 'PF_ALL_Change' -AccessRights PublishingEditor -Confirm:$false -erroraction silentlycontinue
  }
}

$getpfcmd = "get-publicfolder -identity $pfroot -server $pfserver -Recurse -resultsize unlimited"

invoke-expression $getpfcmd | foreach {
    fixacl -pfname $_.Identity
}