Friday, September 16, 2011

Getting Size and Item details for single folders in Exchange 2003 via Powershell

While this is now something you can do in one line in Exchange 2007 and 2010 if your migrating or managing 2000/3 you may want to get the Size and Item Count details of one particular mailbox folder for all users on a server eg how big the Inbox,SentItems or Calendar folder is. In Exchange 2003 you could get the Mailbox Size via WMI but to get an individual folder size you need to access the Mailbox itself (eg you can use pfdavadmin etc). To do this via Power shell for all users on the server you first need an ADSI query to get all the mailboxes on a particular server then you can use with WebDAV via the virtual admin root or MAPI via RDO\Redemption  http://www.dimastr.com/redemption/ which works well in Powershell. I have two scripts that use show how do to this using each of these API's which I've posted a downloadable copy here

To run these scripts you need to use the Netbios name of the server as a commandline parameter the RDO version of the script looks like


$snServerName = $args[0]

$Global:rptCollection = @()

function QueryMailbox($mb){
$mb
$rdoSession = new-object -com Redemption.RDOSession
$rdoSession.LogonExchangeMailbox($SmtpAddress,$snServerName)
$calendar = $rdoSession.Stores.DefaultStore.GetDefaultFolder(9)




$Itmcnt = "" | select DisplayName,SMTPAddress,ItemCount,Size
$Itmcnt.DisplayName = $displayName
$Itmcnt.SMTPAddress = $SmtpAddress
$Itmcnt.ItemCount = $calendar.Items.Count
$Itmcnt.Size = [System.Math]::Round(($calendar.Fields(235405315) /1024),2)
$Global:rptCollection += $Itmcnt
$Itmcnt
$rdoSession.logoff()
}

function GetUsers(){
$root = [ADSI]'LDAP://RootDSE'
$cfConfigRootpath = "LDAP://" + $root.ConfigurationNamingContext.tostring()
$dfDefaultRootPath = "LDAP://" + $root.DefaultNamingContext.tostring()
$configRoot = [ADSI]$cfConfigRootpath
$dfRoot = [ADSI]$dfDefaultRootPath
$searcher = new-object System.DirectoryServices.DirectorySearcher($configRoot)
$searcher.Filter = '(&(objectCategory=msExchExchangeServer)(cn=' + $snServerName  + '))'
$searcher.PropertiesToLoad.Add("cn")
$searcher.PropertiesToLoad.Add("gatewayProxy")
$searcher.PropertiesToLoad.Add("legacyExchangeDN")
$searcher1 = $searcher.FindAll()
foreach ($server in $searcher1){
    $snServerEntry = New-Object System.DirectoryServices.directoryentry
        $snServerEntry = $server.GetDirectoryEntry()
    $snServerName = $snServerEntry.cn
    $snExchangeDN = $snServerEntry.legacyExchangeDN
}
$searcher.Filter = '(&(objectCategory=msExchRecipientPolicy)(cn=Default Policy))'
$searcher1 = $searcher.FindAll()
foreach ($recppolicies in $searcher1){
         $gwaddrrs = New-Object System.DirectoryServices.directoryentry
        $gwaddrrs = $recppolicies.GetDirectoryEntry()
    foreach ($address in $gwaddrrs.gatewayProxy){
        if($address.Substring(0,5) -ceq "SMTP:"){$dfAddress = $address.Replace("SMTP:@","")}
    }   
   
}
$arMbRoot = "https://" + $snServerName + "/exadmin/admin/" + $dfAddress + "/mbx/"
$gfGALQueryFilter =  "(&(&(&(& (mailnickname=*)(!msExchHideFromAddressLists=TRUE)(| (&(objectCategory=person)" `
+ "(objectClass=user)(msExchHomeServerName=" + $snExchangeDN + ")) )))))"
$dfsearcher = new-object System.DirectoryServices.DirectorySearcher($dfRoot)
$dfsearcher.Filter = $gfGALQueryFilter
$searcher2 = $dfsearcher.FindAll()
foreach ($uaUsers in $searcher2){
         $uaUserAccount = New-Object System.DirectoryServices.directoryentry
        $uaUserAccount = $uaUsers.GetDirectoryEntry()
    foreach ($address in $uaUserAccount.proxyaddresses){
        if($address.Substring(0,5) -ceq "SMTP:"){$uaAddress = $address.Replace("SMTP:","")}
    }
    $SmtpAddress = $uaAddress
    $displayName = $uaUserAccount.DisplayName[0]
    QueryMailbox($uaAddress)
}
}

GetUsers
$Global:rptCollection | Export-Csv -NoTypeInformation c:\mailbox.csv

5 comments:

Remko Weijnen said...

PR_MESSAGE_SIZE is of type PT_LONG so it will overflow to -1 for very large mailboxes (> 4GB).

Better to use MESSAGE_SIZE_EXTENDED instead.

Anonymous said...

I can't figure out how to use this script. I am trying to get calendar size for each mailbox on an Exchange 2003 server named "Exch". I am trying to run the webdav script from a 2008 DC. Can you please give me the necessary steps to get this working. Thanks for your help!

Here is what I am currently receiving when running the script.

PS U:\> C:\atpinfoWebDAV.ps1

GAC Version Location
--- ------- --------
True v2.0.50727 C:\Windows\assembly\GAC
True v2.0.50727 C:\Windows\assembly\GAC
0
1
2
An error occurred while enumerating through a
er is invalid..
At C:\atpinfoWebDAV.ps1:95 char:8
+ foreach <<<< ($server in $searcher1){
+ CategoryInfo : InvalidOperatio
tion
+ FullyQualifiedErrorId : BadEnumeration

An error occurred while enumerating through a
E)(| (&(objectCategory=person)(objectClass=us
At C:\atpinfoWebDAV.ps1:117 char:8
+ foreach <<<< ($uaUsers in $searcher2){
+ CategoryInfo : InvalidOperatio
tion
+ FullyQualifiedErrorId : BadEnumeration

Glen said...

Haven't ever seen that error before you don't have to run this from a server just any workstation that is connected to the domain. Because this is access some of the properties of object within the configuration partition of Active directory It maybe a problem if your running the script with constrained permissions. I'd try running the script from a normal workstation with Admin rights.

Cheers
Glen

Anonymous said...

Thanks for such a quick response. Do I need to change anything in the script aside from the credentials, username, passwd, etc? Are there any settings I need to check on the exchange server to ensure this will run properly? Thanks!

Glen said...

You need to set the credentials that are going to be used for the WebDAV call in the following variables

$username = "userName"
$password = "password"
$domain = "domain"

This user need to have delegated Exchange Admin rights

The AD calls will use the currently logged on user

Cheers
Glen