Filtering Output From PFDAVAdmin Or ExFolders

One of the strengths of the PFDAVAdmin and ExFolders tools is that they can perform an operation against a lot of public folders or mailboxes at once. If you’re doing some sort of export, this can generate a lot of output. So how can you filter the output from PFDAVAdmin or ExFolders to give you just what you want?

There are several types of export output you can generate with these tools. In this post, I’m going to describe one particular example. For this scenario, let’s say you want to identify any mailboxes where the mailbox owner has granted permissions on their calendar to some other user.

Since we want to look at calendar permissions, then we obviously want to start by using either PFDAVAdmin or ExFolders to connect to the mailbox database we’re concerned with from File->Connect. Then, we would usually go to Tools->Export Permissions. Both tools will generate output that’s very similar, but I want to highlight a few differences.

Differences between PFDAVAdmin and ExFolders permission exports

Here’s an export of Calendar permissions for one mailbox from PFDAVAdmin:

SETACL Mailboxes\Administrator\Top of Information Store\Calendar BILONG\test12 Editor BILONG\test11 Reviewer BILONG\test10 None NO

Here is the same Calendar permissions exported using ExFolders:

SETACL Mailboxes\administrator@contoso.com\Top of Information Store\Calendar BILONG\test12 Editor FreeBusyDetails BILONG\test11 Reviewer FreeBusyDetails BILONG\test10 FreeBusyDetails Default FreeBusyBasic Anonymous None

First, let me point out some things that apply to both. These lines are tab-delimited, although the blog formatting seems to have converted them to spaces here. Also, each line starts with SETACL, which is what tells the importing tool that the line contains permissions. The tab-delimited line starting with SETACL is the syntax used with the old pfadmin tool for Exchange 5.5, and since PFDAVAdmin was written so that imports/exports would be compatible with that old tool, this syntax has stuck around. When we have multiple permissions for a single entity, those permissions are separated by spaces. So basically, the format is SETACL<tab>Folder Path<tab>Entity1<tab>Permissions<tab>Entity2<tab>Permissions, etc, where Permissions may contain multiple space-separated keywords.

Although public folder permissions imports/exports are compatible from pfadmin to PFDAVAdmin to ExFolders, mailbox permissions exports are not. Pfadmin never supported them, and PFDAVAdmin uses a different folder path syntax than ExFolders, which you can see here in the second column of the export. PFDAVAdmin just uses a name, whereas ExFolders uses an actual SMTP address to guarantee uniqueness.

Also, note that I’ve exported the permissions in the domain\user format, just because I find that easiest to read, but you could use legacyExchangeDN format if you wanted to.

The next thing to notice is that the ExFolders output contains more permissions for each entity. PFDAVAdmin says that test12 just has Editor, whereas ExFolders says test12 has Editor and FreeBusyDetails. This is because PFDAVAdmin does not support the new, more granular Free/Busy permissions that were introduced in Exchange 2007. Those permissions are stored in a separate ACL that PFDAVAdmin can’t read, so it simply doesn’t see them. ExFolders sees them just fine, so it includes them in the output. FreeBusyBasic is what appears as “Free/Busy time” in Outlook 2007, while FreeBusyDetails is what appears as “Free/Busy time, subject, location”. If you have something like Editor or Reviewer, you automatically get FreeBusyDetails in addition to the other role.

One last difference is that PFDAVAdmin includes a “NO” at the end of the line. This is another leftover from the pfadmin format. It was used to tell pfadmin to not propagate these changes to subfolders. PFDAVAdmin always ignores a YES or NO keyword during import – this was only included so you could export from PFDAVAdmin and import on pfadmin. This was finally dropped from ExFolders entirely, since hopefully no one is exporting their Exchange 2007 or 2010 permissions and trying to import them on Exchange 5.5!

Filtering from within PFDAVAdmin and ExFolders

One way to reduce the output you get from the tools is to filter the export operation itself, but you can’t do this from Tools->Export Permissions. Instead, you need to go to Tools->Custom Bulk Operation. This is a little more complicated than running a normal export, so let’s look at some screenshots.

When you choose Custom Bulk Operation, you’ll be presented with the following dialog.

cbo1

This screen allows you to add multiple operations to run all at once. It also allows you to configure a filter that controls which folders the operations will fire on. For now, let’s skip the filter and add the one operation we want. Click Add.

cbo2

We’re interesting in Folder Permissions, so that’s the operation we choose here. Click OK.

cbo3

Now we can configure the Folder Permissions operation. For our purposes here, we want to do an Export. When you choose Export, the dialog changes to let you specify an export file. Also, you can see I’ve chosen the domain\user format for the export.

Notice that you can also specify a filter on the operation itself. In this way, you can run a bulk operation that does different things to different folders, but using multiple operations with different filters. However, for our purposes here, we’ll leave this filter alone. Click OK.

cbo4

OK, we’ve added our Folder Permissions export operation, so you should see it in the Operations window, but that operation is configured to run against all folders. Now we’re going to configure an Overall Filter. The Overall Filter means that we will only run any listed operations against folders that match the filter. Otherwise we skip ALL configured operations.

The filter syntax is LDAP-like, but instead of Active Directory property names, we use MAPI property tag values. For this, we only want folders named Calendar, so I’ve configured a filter that specifies PR_DISPLAY_NAME (0x3001001E) is equal to Calendar. If the display name is Calendar, we’ll fire the export operation, otherwise we’ll skip it.

But what if you have calendars in foreign languages? The folder might not be called Calendar in that case. You can configure a filter to match the different names, but this can get cumbersome. For instance, the filter (|(0x3001001E=Calendar)(0x3001001E=OtherName)(0x3001001E=ThirdName)) would match folders named either “Calendar”, or “OtherName”, or “ThirdName”, because the bar character “|” is an OR.

Another option is to filter on PR_CONTAINER_CLASS (0x3613001E), which will be IPF.Appointment for a calendar folder. The appropriate filter in that case would be “(&(0x3613001E=IPF.Appointment))”. Of course, it’s possible the user could have multiple calendar folders, although that’s probably not a very common scenario.

There are more graceful ways to identify the mailbox calendar programmatically, but those are not exposed through the filtering mechanism at this time. In any case, choose the filter that works best for your scenario. When you’re ready, click OK, and the operation will start. When it finishes, you’ll only have output for the folders that matched your filter.

Filtering the output after the fact

Filtering within the tools themselves can be useful, but it also has its limitations. What if you decide you want to check for other shared folders, like the Inbox? Or what if you decide you want to review the Default permissions for all the mailbox folders? It can be useful to just let the tool generate a ton of data, and then use a Powershell script to parse out what you’re interested in later. For our example here, we want to identify users who have shared their Calendar folders. We can let the tool narrow the exported data to just Calendar folders, but we still have to resort to other methods to identify the ones that are shared. For this, we’ll create a new Powershell script called Find-SharedFolders.ps1.

The first thing we need to do with our script is decide how to read the export file. The Get-Content cmdlet provides an easy way to read a file, but the problem is that it reads the entire file and stores it in memory. If the file is really big, this can be a problem. For that reason, I usually prefer to use a StreamReader and just deal with one line at a time.

$exportFile = "C:\FolderPermissions.txt"
$reader = new-object System.IO.StreamReader($exportFile)
while ($null -ne ($buffer = $reader.ReadLine()))
{
# do stuff here
}

Now our script is set up to read each line from our export file, so we just need to replace the “do stuff here” comment with code to actually do something with each line. Here’s the stuff that replaces the comment.

$columns = $buffer.Split(@(' ')) # <-that should be a tab character between the single quotes
# if the first column doesn’t say SETACL, we’re not interested
if ($columns[0] -eq "SETACL")
{
# the second column is the folder path
$folderPath = $columns[1]
# start by assuming it’s not shared
$isShared = $false
#now deal with the remaining columns
for ($x = 2; $x -lt $columns.Length; $x++)
{
if ($columns[$x] -eq "YES" -or $columns[$x] -eq "NO")
{
# We don’t care about the YES or NO keywords
continue
}

          $entity = $columns[$x]
$perms = $columns[$x+1].Split(@(' ')) # <-that should be a space
foreach ($perm in $perms)
{
# Here’s where we need to decide what we’re really interested in.
# I’m going to assume we don’t care about FreeBusyBasic or FreeBusyDetails,
# and we want to look for stuff that lets people do more than just
# see availability.
if ($perm -ne "FreeBusyBasic" -and $perm -ne "FreeBusyDetails" -and $perm -ne "None")
{
# We found something interesting! Flag it as shared and stop looking at perms.
$isShared = $true
break
}
}

          # If we flagged it as shared, we don’t need to evaluate any more perms.
# Display the folder path and break out.
if ($isShared)
{
$folderPath
break
}

          # Otherwise, we must have found some perms to evaluate, so we need to
# increment x again to skip them and get to the next entity.
$x++
}
}

Now we have a script that will run against either the PFDAVAdmin export or the ExFolders export. In the case of PFDAVAdmin, we’ll never see FreeBusyBasic or FreeBusyDetails, so we’re effectively just looking for anything other than None. In the case of ExFolders, we’ll ignore the availability permissions and look for any roles that give more permissions than those.

In the output stream, the script just lists the folders that match the criteria we’re interested in. You would then need to search for that folder in the export and see who it’s shared to. It wouldn’t be hard to add that info to the output stream as well, which would save you the trouble of looking for it.

To run the script, just save it somewhere, change to that folder in Powershell, and run “.\Find-SharedFolders” (assuming you named it Find-SharedFolders.ps1). Note that you won’t be able to get that tab character to stick in the Powershell ISE (or if there’s a way I just don’t know what it is), so I recommend editing this particular script in Notepad.

I hope this example was useful. If you have other similar scenarios you’d like me to discuss, post a comment somewhere and let me know. I can’t promise anything, but maybe I can address it in a future post.