Monday, January 17, 2011

Calculating Mailbox Sizes using Exchange Web Services and Powershell

Normally if you want to work out the size of a mailbox or the size of a mailbox folder as an administrator you would use get-mailboxstatistics and get-mailboxfolderstatistics the Exchange Management Shelll cmdlets which are the fastest and easiest way of retrieving this information on 2007 and 2010. However if you want to get the Mailbox size using normal user rights or the EMS cmdlets aren't an option then EWS can be used. There is no one property inside a mailbox that can be used to get the total size of a mailbox so like you needed to do in 2003 and earlier to calculate the size of a mailbox you need to get the size of each mailbox folder then sum these together. To get the Size of the Mailbox Folder and Deleted Items within a folder requires the use of the following extended Mapi properties

PR_MESSAGE_SIZE_EXTENDED and PR_DELETED_MESSAGE_SIZE_EXTENDED

To get the properties on all of the folders in a Mailbox a Deep Traversal findfolders operations from the Root of the Mailbox can be used.

One of useful things you can do with EWS that you can't do in EMS with the cmdlets is filter this query by the Mapi FolderClass (which is different from the folderscope property). In the large script posted below I've commented out the filter to do this but the lines are

##$folderItemType = "IPF.Note"
##$sfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::FolderClass, $folderItemType)
##$fiResult = $Service.FindFolders($folderidcnt,$sfSearchFilter,$fvFolderView)


The normal EWS Managed API power shell script I've put a download of here the code looks like

$MailboxName = "user@domain.com"
##$folderItemType = "IPF.Note"
$rptCollection = @()


$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)


$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$sidbind = "LDAP://<SID=" + $windowsIdentity.user.Value.ToString() + ">"
$aceuser = [ADSI]$sidbind
$service.AutodiscoverUrl($aceuser.mail.ToString(),{$true})

$TotalItemCount = 0
$TotalItemSize = 0

"Checking : " + $MailboxName
$folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
$fvFolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(10000)
$fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep;
$psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$PR_MESSAGE_SIZE_EXTENDED = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(3592,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Long);
$PR_DELETED_MESSAGE_SIZE_EXTENDED = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(26267,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Long);
$PR_DELETED_MSG_COUNT = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(26176,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);
$psPropertySet.Add($PR_MESSAGE_SIZE_EXTENDED);
$psPropertySet.Add($PR_DELETED_MESSAGE_SIZE_EXTENDED);
$psPropertySet.Add($PR_DELETED_MSG_COUNT);
$fvFolderView.PropertySet = $psPropertySet;
##$sfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::FolderClass, $folderItemType)
##$fiResult = $Service.FindFolders($folderidcnt,$sfSearchFilter,$fvFolderView)
$fiResult = $Service.FindFolders($folderidcnt,$fvFolderView)
foreach($ffFolder in $fiResult.Folders){
$TotalItemCount = $TotalItemCount + $ffFolder.TotalCount;
$FolderSize = $null;
if ($ffFolder.TryGetProperty($PR_MESSAGE_SIZE_EXTENDED,[ref] $FolderSize))
{
$TotalItemSize = $TotalItemSize + [Int64]$FolderSize
}
$DeletedItemFolderSize = $null;
if ($ffFolder.TryGetProperty($PR_DELETED_MESSAGE_SIZE_EXTENDED, [ref] $DeletedItemFolderSize))
{
$TotalDeletedItemSize = $TotalDeletedItemSize + [Int64]$DeletedItemFolderSize
}
$DeletedMsgCount = $null;
if ($ffFolder.TryGetProperty($PR_DELETED_MSG_COUNT, [ref] $DeletedMsgCount))
{
$TotalDeletedItemCount = $TotalDeletedItemCount + [Int32]$DeletedMsgCount;
}
}
$rptobj = "" | select DisplayName,LegacyDN,TotalItemSize,TotalItemCount,TotalDeletedItemSize,TotalDeletedItemCount
$rptobj.DisplayName = $_.DisplayName
$rptobj.LegacyDN = $_.LegacyExchangeDN
$rptobj.TotalItemCount = $TotalItemCount
$rptobj.TotalItemSize = $TotalItemSize
$rptobj.TotalDeletedItemSize = $TotalDeletedItemSize
$rptobj.TotalDeletedItemCount = $TotalDeletedItemCount
$rptCollection += $rptobj

$rptCollection

4 comments:

Chris said...

Do you have a version that works kind of in the opposite where you can take a user and apply permissions to all mailboxes on the Exchange server?

Example - Reviewer Calendar access for User A to all other users.

Rick said...

Rick asks...

I am in need of a script to pull the following mapi properties using EWS API: (PR_RETENTION_DATE, PR_RETENTION_PERIOD)

I read through your posts pulling some mapi properties, so I know it can be done; however some of these scripts are a little complex for my taste. Can you provide a code sample (powershell preferred) of how to pull the following information for items in a mailbox, please respond ASAP.

The Mapi property values are:


PR_RETENTION_DATE,PidTagRetentionDate,ptagRetentionDate
0x301C0040
PT_SYSTIME
00:00:00.000 PM mm/dd/yyyy

PR_RETENTION_FLAGS,PidTagRetentionFlags,ptagRetentionFlags
0x301D0003
PT_LONG
0

PR_RETENTION_PERIOD,PidTagRetentionPeriod,ptagRetentionPeriod
0x301A0003
PT_LONG
0


SCRIPT OUTPUT: Subject, From, ParentFolder, PR_RETENTION_DATE, PR_RETENTION_PERIOD

Rick said...

In response to my own post. I was able to figure out how to expose the mapi properties I was seeking.

Nick said...

Also, for those of you looking for a way to get the item count, you can use the MAPI property PR_CONTENT_COUNT hex:0x3602 dec:13826