Microsoft KB Archive/320071

= How to programmatically get the size of mailboxes in Exchange =

Article ID: 320071

Article Last Modified on 10/25/2007

-

APPLIES TO


 * Microsoft Exchange Server 2003 Enterprise Edition
 * Microsoft Exchange Server 2003 Standard Edition
 * Microsoft Exchange 2000 Server Standard Edition
 * Microsoft Exchange Server 5.5 Standard Edition

-



This article was previously published under Q320071



SUMMARY
This article describes how to programmatically retrieve information about the size of mailboxes on a server that is running Microsoft Exchange by using Microsoft Visual C, Microsoft Visual C++, Microsoft Visual Basic, and Microsoft Visual Basic Scripting Edition (VBScript).



Extended MAPI approach
Programming Languages Available: Visual C, Visual C++

Exchange Server Versions: Exchange Server 5.5, Exchange 2000, and Exchange 2003

Extended MAPI provides the IExchangeManageStore interface to obtain management information from an Exchange information store. This interface provides the GetMailboxTable function, which returns an IMAPITable interface that contains information about the mailboxes on a particular server. Note that this function requires administrative access to the server that is running Exchange Server.

This table includes a column that provides information about the size of each mailbox. The PR_MESSAGE_SIZE property contains the size (in bytes) of the mailbox.

For additional information, visit the following Microsoft Developer Network (MSDN) Web site:

IExchangeManageStore::GetMailboxTable

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/exchserv/html/intrface_24it.asp

For additional information, click the following article number to view the article in the Microsoft Knowledge Base:

200160 How to loop through mailboxes on Exchange using GetMailboxTable

CDO 1.21 approach
Programming Languages Available: VBScript, Visual Basic, Visual C, Visual C++

Exchange Server Versions: Exchange Server 5.5, Exchange 2000, and Exchange 2003

You can use Collaboration Data Objects (CDO) 1.21 to check the same property on a user mailbox store through the CDO InfoStore object. In this approach, your application must log on to a mailbox before the application can check this property. This means that your application must have access to all mailboxes on the server. This approach also requires that you generate a list of mailboxes on the server and then loop through them in code.

The following sample is a simple VBScript code sample that can check this property on a mailbox. To use this sample, paste the following code in a new text file, and then name the file Mailboxsize.vbs: 'This script logs on to a server that is running Exchange Server and 'displays the current number of bytes that are used in the user's 'mailbox and the number of messages.

' USAGE: cscript MailboxSize.vbs SERVERNAME MAILBOXNAME

' This requires that CDO 1.21 is installed on the computer. ' This script is provided AS IS. It is intended as a SAMPLE only. ' Microsoft offers no warranty or support for this script. ' Use at your own risk.

' Get command line arguments. Dim obArgs Dim cArgs

Set obArgs = WScript.Arguments cArgs = obArgs.Count

Main

Sub Main Dim oSession Dim oInfoStores Dim oInfoStore Dim StorageUsed Dim NumMessages Dim strProfileInfo Dim sMsg

On Error Resume Next

If cArgs <> 2 Then WScript.Echo &quot;Usage: cscript MailboxSize.vbs SERVERNAME MAILBOXNAME&quot; Exit Sub End If

'Create Session object. Set oSession = CreateObject(&quot;MAPI.Session&quot;) if Err.Number <> 0 Then sMsg = &quot;Error creating MAPI.Session.&quot; sMsg = sMsg & &quot;Make sure CDO 1.21 is installed. &quot; sMsg = sMsg & Err.Number & &quot; &quot; & Err.Description WScript.Echo sMsg Exit Sub End If  strProfileInfo = obArgs.Item(0) & vbLf & obArgs.Item(1)

'Log on. oSession.Logon, , False, True, , True, strProfileInfo if Err.Number <> 0 Then sMsg = &quot;Error logging on: &quot; sMsg = sMsg & Err.Number & &quot; &quot; & Err.Description WScript.Echo sMsg WScript.Echo &quot;Server: &quot; & obArgs.Item(0) WScript.Echo &quot;Mailbox: &quot; & obArgs.Item(1) Set oSession = Nothing Exit Sub End If

'Grab the information stores. Set oInfoStores = oSession.InfoStores if Err.Number <> 0 Then

sMsg = &quot;Error retrieving InfoStores Collection: &quot; sMsg = sMsg & Err.Number & &quot; &quot; & Err.Description WScript.Echo sMsg WScript.Echo &quot;Server: &quot; & obArgs.Item(0) WScript.Echo &quot;Mailbox: &quot; & obArgs.Item(1) Set oInfoStores = Nothing Set oSession = Nothing Exit Sub End If  'Loop through information stores to find the user's mailbox. For Each oInfoStore In oInfoStores If InStr(1, oInfoStore.Name, &quot;Mailbox - &quot;, 1) <> 0 Then '&HE080003 = PR_MESSAGE_SIZE StorageUsed = oInfoStore.Fields(&HE080003) if Err.Number <> 0 Then sMsg = &quot;Error retrieving PR_MESSAGE_SIZE: &quot; sMsg = sMsg & Err.Number & &quot; &quot; & Err.Description WScript.Echo sMsg WScript.Echo &quot;Server: &quot; & obArgs.Item(0) WScript.Echo &quot;Mailbox: &quot; & obArgs.Item(1) Set oInfoStore = Nothing Set oInfoStores = Nothing Set oSession = Nothing Exit Sub End If        '&H33020003 = PR_CONTENT_COUNT NumMessages = oInfoStore.Fields(&H36020003)

if Err.Number <> 0 Then

sMsg = &quot;Error Retrieving PR_CONTENT_COUNT: &quot; sMsg = sMsg & Err.Number & &quot; &quot; & Err.Description WScript.Echo sMsg WScript.Echo &quot;Server: &quot; & obArgs.Item(0) WScript.Echo &quot;Mailbox: &quot; & obArgs.Item(1) Set oInfoStore = Nothing Set oInfoStores = Nothing Set oSession = Nothing Exit Sub End If

sMsg = &quot;Storage Used in &quot; & oInfoStore.Name sMsg = sMsg & &quot; (bytes): &quot; & StorageUsed WScript.Echo sMsg WScript.Echo &quot;Number of Messages: &quot; & NumMessages End If  Next

' Log off. oSession.Logoff

' Clean up memory. Set oInfoStore = Nothing Set oInfoStores = Nothing Set oSession = Nothing End Sub

ActiveX Data Objects (ADO) approach
Programming Languages Available: VBScript, Visual Basic, Visual C, Visual C++

Exchange Server Versions: Exchange 2000 and Exchange 2003

In Exchange 2000 and Exchange 2003, you can access the Exchange information store through ActiveX Data Objects (ADO). No property that is stored on the mailbox contains the total size. However, each folder in a user mailbox has its size stored in a field that is named http://schemas.microsoft.com/mapi/proptag/x0e080003. This corresponds to the MAPI property, PR_MESSAGE_SIZE.

By adding the size of all of the folders in a user mailbox, the total size of the mailbox can be computed. To do this, you use a SHALLOW traversal to recursively traverse the folders in the mailbox. Although you can use a DEEP traversal, this approach is avoided because of the issues that DEEP traversal raises. For additional information about the issues with a DEEP traversal, click the following article number to view the article in the Microsoft Knowledge Base:

216076 Accessing Information Store folders may become slow

In this approach, you must run your code on the server that is running Exchange 2000. OLE DB Provider for Exchange (EXOLEDB) cannot access mailboxes remotely.

The following sample is a simple VBScript code sample that can retrieve the size of a mailbox. To use this sample, paste the following code in a new text file, and then name the file Mailboxsize.vbs: 'This script logs on to a server that is running Exchange 2000 or 2003 and 'displays the current number of bytes that are used in the user's 'mailbox.

' USAGE: cscript MailboxSize.vbs DOMAINNAME MAILBOXNAME

' You must run this code on the computer that is running Exchange 2000 or 2003. ' This script is provided AS IS. It is intended as a SAMPLE only. ' Microsoft offers no warranty or support for this script. ' Use at your own risk.

' Get command line arguments

Dim obArgs Dim cArgs Dim iSize

Set obArgs = WScript.Arguments cArgs = obArgs.Count

Main

Sub Main Dim sConnString

On Error Resume Next

If cArgs <> 2 Then WScript.Echo &quot;Usage: cscript MailboxSize.vbs DOMAINNAME MAILBOXNAME&quot; Exit Sub End If

' Set up connection string to mailbox. sConnString = &quot;file://./backofficestorage/&quot; & obArgs.Item(0) sConnString = sConnString & &quot;/mbx/&quot; & obArgs.Item(1) & &quot;/NON_IPM_SUBTREE&quot; WScript.Echo sConnString

iSize = 0

RecurseFolder(sConnString)

WScript.Echo &quot;Mailbox Size: &quot; & iSize End Sub

Public Sub RecurseFolder(sConnString) Dim oConn Dim oRecSet Dim sSQL

' Set up SQL SELECT statement. sSQL = &quot;SELECT &quot;&quot;http://schemas.microsoft.com/mapi/proptag/x0e080003&quot;&quot;, &quot; sSQL = sSQL & &quot;&quot;&quot;DAV:href&quot;&quot;, &quot; sSQL = sSQL & &quot;&quot;&quot;DAV:hassubs&quot;&quot; &quot; sSQL = sSQL & &quot;FROM SCOPE ('SHALLOW TRAVERSAL OF &quot;&quot;&quot; & sConnString  sSQL = sSQL & &quot;&quot;&quot;') WHERE &quot;&quot;DAV:isfolder&quot;&quot; = true&quot; WScript.Echo sSQL

' Create Connection object. Set oConn = CreateObject(&quot;ADODB.Connection&quot;) if Err.Number <> 0 then WScript.Echo &quot;Error creating ADO Connection object: &quot; & Err.Number & &quot; &quot; & Err.Description end if

' Create RecordSet object. Set oRecSet = CreateObject(&quot;ADODB.Recordset&quot;) if Err.Number <> 0 then WScript.Echo &quot;Error creating ADO RecordSet object: &quot; & Err.Number & &quot; &quot; & Err.Description Set oConn = Nothing Exit Sub end if

' Set provider to EXOLEDB. oConn.Provider = &quot;Exoledb.DataSource&quot;

' Open connection to folder. oConn.Open sConnString if Err.Number <> 0 then WScript.Echo &quot;Error opening connection: &quot; & Err.Number & &quot; &quot; & Err.Description Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

' Open Recordset of all subfolders in folder. oRecSet.CursorLocation = 3 oRecSet.Open sSQL, oConn.ConnectionString if Err.Number <> 0 then WScript.Echo &quot;Error opening recordset: &quot; & Err.Number & &quot; &quot; & Err.Description oRecSet.Close oConn.Close Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

if oRecSet.RecordCount = 0 then oRecSet.Close oConn.Close Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

' Move to first record. oRecSet.MoveFirst if Err.Number <> 0 then WScript.Echo &quot;Error moving to first record: &quot; & Err.Number & &quot; &quot; & Err.Description oRecSet.Close oConn.Close Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

' Loop through all of the records, and then add the size of the ' subfolders to obtain the total size. While oRecSet.EOF <> True ' Increment size. iSize = iSize + oRecSet.Fields.Item(&quot;http://schemas.microsoft.com/mapi/proptag/x0e080003&quot;)

' If the folder has subfolders, recursively call RecurseFolder to process them. If oRecSet.Fields.Item(&quot;DAV:hassubs&quot;) = True then RecurseFolder oRecSet.Fields.Item(&quot;DAV:href&quot;) End If     ' Move to next record. oRecSet.MoveNext if Err.Number <> 0 then WScript.Echo &quot;Error moving to next record: &quot; & Err.Number & &quot; &quot; & Err.Description Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if  wend

' Close Recordset and Connection. oRecSet.Close if Err.Number <> 0 then WScript.Echo &quot;Error closing recordset: &quot; & Err.Number & &quot; &quot; & Err.Description Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

oConn.Close if Err.Number <> 0 then WScript.Echo &quot;Error closing connection: &quot; & Err.Number & &quot; &quot; & Err.Description Set oRecSet = Nothing Set oConn = Nothing Exit Sub end if

' Clean up memory. Set oRecSet = Nothing Set oConn = Nothing End Sub For additional information about this topic and a Visual C++ sample that retrieves the size of mailboxes, click the following article number to view the article in the Microsoft Knowledge Base:

291368 How to determine the size of Exchange 2000 Server mailbox with ADO in C++

WebDAV approach
Languages: VBScript, Visual Basic, Visual C

Exchange Server Versions: Exchange 2000 and Exchange 2003

You can also use WebDAV similarly to the ADO approach. The property and the algorithm are the same in that you can add the values of http://schemas.microsoft.com/mapi/proptag/x0e080003 from all of the subfolders in a mailbox. One advantage of using WebDAV instead of ADO is that the code does not have to run on the computer that is running Exchange 2000 or Exchange 2003.

To use this sample, paste the following code in a new text file, and then name the file Mailboxsize.vbs: 'This script logs on to a server that is running Exchange Server and 'displays the current number of bytes that are used in the user's 'mailbox.

' USAGE: cscript MailboxSize.vbs SERVERNAME MAILBOXNAME USERNAME PASSWORD

' SERVERNAME: Name of your Exchange Server

' MAILBOXNAME: Your alias (Note: depending on your environment, you may need to use the portion of your ' SMTP address left of the '@' symbol instead of your alias.

' USERNAME: Your domainname\username '

' PASSWORD: Your domain password ' This script is provided AS IS. It is intended as a SAMPLE only. ' Microsoft offers no warranty or support for this script. ' Use at your own risk.

' Get command line arguments.

Dim obArgs Dim cArgs Dim iSum

Set obArgs = WScript.Arguments cArgs = obArgs.Count

Main

Sub Main Dim sUrl Dim sMsg

On Error Resume Next

iSum = 0

' Check argument count. If cArgs <> 4 Then sMsg = &quot;Usage: cscript MailboxSize.vbs &quot; sMsg = sMsg & &quot;SERVERNAME MAILBOXNAME USERNAME PASSWORD&quot; WScript.Echo sMsg Exit Sub End If

sUrl = &quot;http://&quot; & obArgs.Item(0) & &quot;/exchange/&quot; & obArgs.Item(1) & &quot;/NON_IPM_SUBTREE&quot; wscript.echo sUrl

RecurseFolder(sUrl)

WScript.Echo &quot;Mailbox Size: &quot; & iSum End Sub

Public Sub RecurseFolder(sUrl) Dim oXMLHttp Dim oXMLDoc Dim oXMLSizeNodes Dim oXMLHREFNodes Dim oXMLHasSubsNodes Dim sQuery

Set oXMLHttp = CreateObject(&quot;Microsoft.xmlhttp&quot;) If Err.Number <> 0 Then WScript.Echo &quot;Error Creating XML object&quot; WScript.Echo Err.Number & &quot;: &quot; & Err.Description Set oXMLHttp = Nothing End If

' Open DAV connection. oXMLHttp.open &quot;SEARCH&quot;, sUrl, False, obArgs.Item(2), obArgs.Item(3) If Err.Number <> 0 Then WScript.Echo &quot;Error opening DAV connection&quot; WScript.Echo Err.Number & &quot;: &quot; & Err.Description Set oXMLHttp = Nothing End If

' Set up query. sQuery = &quot;&quot; sQuery = sQuery & &quot;&quot; sQuery = sQuery & &quot;SELECT &quot;&quot;http://schemas.microsoft.com/&quot; sQuery = sQuery & &quot;mapi/proptag/x0e080003&quot;&quot;, &quot;&quot;DAV:hassubs&quot;&quot; FROM SCOPE &quot; sQuery = sQuery & &quot;('SHALLOW TRAVERSAL OF &quot;&quot;&quot; & sUrl & &quot;&quot;&quot;') &quot; sQuery = sQuery & &quot;WHERE &quot;&quot;DAV:isfolder&quot;&quot; = true&quot; sQuery = sQuery & &quot;&quot; sQuery = sQuery & &quot;&quot;

' Set request headers. oXMLHttp.setRequestHeader &quot;Content-Type&quot;, &quot;text/xml&quot; oXMLHttp.setRequestHeader &quot;Translate&quot;, &quot;f&quot; oXMLHttp.setRequestHeader &quot;Depth&quot;, &quot;0&quot; oXMLHttp.setRequestHeader &quot;Content-Length&quot;, &quot;&quot; & Len(sQuery)

' Send request. oXMLHttp.send sQuery If Err.Number <> 0 Then WScript.Echo &quot;Error Sending Query&quot; WScript.Echo Err.Number & &quot;: &quot; & Err.Description Set oXMLHttp = Nothing End If

' Load XML. Set oXMLDoc = oXMLHttp.responseXML

' Get the XML nodes that contain the individual sizes. Set oXMLSizeNodes = oXMLDoc.getElementsByTagName(&quot;d:x0e080003&quot;)

' Get the XML nodes that contain the individual HREFs. Set oXMLHREFNodes = oXMLDoc.getElementsByTagName(&quot;a:href&quot;)

' Get the XML nodes that contain the individual HasSubs. Set oXMLHasSubsNodes = oXMLDoc.getElementsByTagName(&quot;a:hassubs&quot;)

' Loop through the nodes, and then add all of the sizes. For i = 0 to oXMLSizeNodes.length - 1 WScript.Echo oXMLHREFNodes.Item(i).nodeTypedValue WScript.Echo &quot;Size: &quot; & oXMLSizeNodes.Item(i).nodeTypedValue iSum = iSum + oXMLSizeNodes.Item(i).nodeTypedValue

' If the folder has subfolders, call your recursive function to      ' process subfolders. If oXMLHasSubsNodes.Item(i).nodeTypedValue = True Then RecurseFolder oXMLHREFNodes.Item(i).nodeTypedValue End If  Next

' Clean up. Set oXMLSizeNodes = Nothing Set oXMLDoc = Nothing Set oXMLHttp = Nothing End Sub

Note In addition to the programmatic methods that are described in this section, you can also export folder size information to a text file by using Exchange System Manager.

Keywords: kbhowto KB320071

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.