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, 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 "Usage: cscript MailboxSize.vbs SERVERNAME MAILBOXNAME"
Exit Sub
End If
'Create Session object.
Set oSession = CreateObject("MAPI.Session")
if Err.Number <> 0 Then
sMsg = "Error creating MAPI.Session."
sMsg = sMsg & "Make sure CDO 1.21 is installed. "
sMsg = sMsg & Err.Number & " " & 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 = "Error logging on: "
sMsg = sMsg & Err.Number & " " & Err.Description
WScript.Echo sMsg
WScript.Echo "Server: " & obArgs.Item(0)
WScript.Echo "Mailbox: " & obArgs.Item(1)
Set oSession = Nothing
Exit Sub
End If
'Grab the information stores.
Set oInfoStores = oSession.InfoStores
if Err.Number <> 0 Then
sMsg = "Error retrieving InfoStores Collection: "
sMsg = sMsg & Err.Number & " " & Err.Description
WScript.Echo sMsg
WScript.Echo "Server: " & obArgs.Item(0)
WScript.Echo "Mailbox: " & 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, "Mailbox - ", 1) <> 0 Then
'&HE080003 = PR_MESSAGE_SIZE
StorageUsed = oInfoStore.Fields(&HE080003)
if Err.Number <> 0 Then
sMsg = "Error retrieving PR_MESSAGE_SIZE: "
sMsg = sMsg & Err.Number & " " & Err.Description
WScript.Echo sMsg
WScript.Echo "Server: " & obArgs.Item(0)
WScript.Echo "Mailbox: " & 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 = "Error Retrieving PR_CONTENT_COUNT: "
sMsg = sMsg & Err.Number & " " & Err.Description
WScript.Echo sMsg
WScript.Echo "Server: " & obArgs.Item(0)
WScript.Echo "Mailbox: " & obArgs.Item(1)
Set oInfoStore = Nothing
Set oInfoStores = Nothing
Set oSession = Nothing
Exit Sub
End If
sMsg = "Storage Used in " & oInfoStore.Name
sMsg = sMsg & " (bytes): " & StorageUsed
WScript.Echo sMsg
WScript.Echo "Number of Messages: " & 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 "Usage: cscript MailboxSize.vbs DOMAINNAME MAILBOXNAME"
Exit Sub
End If
' Set up connection string to mailbox.
sConnString = "file://./backofficestorage/" & obArgs.Item(0)
sConnString = sConnString & "/mbx/" & obArgs.Item(1) & "/NON_IPM_SUBTREE"
WScript.Echo sConnString
iSize = 0
RecurseFolder(sConnString)
WScript.Echo "Mailbox Size: " & iSize
End Sub
Public Sub RecurseFolder(sConnString)
Dim oConn
Dim oRecSet
Dim sSQL
' Set up SQL SELECT statement.
sSQL = "SELECT ""http://schemas.microsoft.com/mapi/proptag/x0e080003"", "
sSQL = sSQL & """DAV:href"", "
sSQL = sSQL & """DAV:hassubs"" "
sSQL = sSQL & "FROM SCOPE ('SHALLOW TRAVERSAL OF """ & sConnString
sSQL = sSQL & """') WHERE ""DAV:isfolder"" = true"
WScript.Echo sSQL
' Create Connection object.
Set oConn = CreateObject("ADODB.Connection")
if Err.Number <> 0 then
WScript.Echo "Error creating ADO Connection object: " & Err.Number & " " & Err.Description
end if
' Create RecordSet object.
Set oRecSet = CreateObject("ADODB.Recordset")
if Err.Number <> 0 then
WScript.Echo "Error creating ADO RecordSet object: " & Err.Number & " " & Err.Description
Set oConn = Nothing
Exit Sub
end if
' Set provider to EXOLEDB.
oConn.Provider = "Exoledb.DataSource"
' Open connection to folder.
oConn.Open sConnString
if Err.Number <> 0 then
WScript.Echo "Error opening connection: " & Err.Number & " " & 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 "Error opening recordset: " & Err.Number & " " & 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 "Error moving to first record: " & Err.Number & " " & 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("http://schemas.microsoft.com/mapi/proptag/x0e080003")
' If the folder has subfolders, recursively call RecurseFolder to process them.
If oRecSet.Fields.Item("DAV:hassubs") = True then
RecurseFolder oRecSet.Fields.Item("DAV:href")
End If
' Move to next record.
oRecSet.MoveNext
if Err.Number <> 0 then
WScript.Echo "Error moving to next record: " & Err.Number & " " & 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 "Error closing recordset: " & Err.Number & " " & Err.Description
Set oRecSet = Nothing
Set oConn = Nothing
Exit Sub
end if
oConn.Close
if Err.Number <> 0 then
WScript.Echo "Error closing connection: " & Err.Number & " " & 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 = "Usage: cscript MailboxSize.vbs "
sMsg = sMsg & "SERVERNAME MAILBOXNAME USERNAME PASSWORD"
WScript.Echo sMsg
Exit Sub
End If
sUrl = "http://" & obArgs.Item(0) & "/exchange/" & obArgs.Item(1) & "/NON_IPM_SUBTREE"
wscript.echo sUrl
RecurseFolder(sUrl)
WScript.Echo "Mailbox Size: " & iSum
End Sub
Public Sub RecurseFolder(sUrl)
Dim oXMLHttp
Dim oXMLDoc
Dim oXMLSizeNodes
Dim oXMLHREFNodes
Dim oXMLHasSubsNodes
Dim sQuery
Set oXMLHttp = CreateObject("Microsoft.xmlhttp")
If Err.Number <> 0 Then
WScript.Echo "Error Creating XML object"
WScript.Echo Err.Number & ": " & Err.Description
Set oXMLHttp = Nothing
End If
' Open DAV connection.
oXMLHttp.open "SEARCH", sUrl, False, obArgs.Item(2), obArgs.Item(3)
If Err.Number <> 0 Then
WScript.Echo "Error opening DAV connection"
WScript.Echo Err.Number & ": " & Err.Description
Set oXMLHttp = Nothing
End If
' Set up query.
sQuery = "<?xml version=""1.0""?>"
sQuery = sQuery & "<g:searchrequest xmlns:g=""DAV:"">"
sQuery = sQuery & "<g:sql>SELECT ""http://schemas.microsoft.com/"
sQuery = sQuery & "mapi/proptag/x0e080003"", ""DAV:hassubs"" FROM SCOPE "
sQuery = sQuery & "('SHALLOW TRAVERSAL OF """ & sUrl & """') "
sQuery = sQuery & "WHERE ""DAV:isfolder"" = true"
sQuery = sQuery & "</g:sql>"
sQuery = sQuery & "</g:searchrequest>"
' Set request headers.
oXMLHttp.setRequestHeader "Content-Type", "text/xml"
oXMLHttp.setRequestHeader "Translate", "f"
oXMLHttp.setRequestHeader "Depth", "0"
oXMLHttp.setRequestHeader "Content-Length", "" & Len(sQuery)
' Send request.
oXMLHttp.send sQuery
If Err.Number <> 0 Then
WScript.Echo "Error Sending Query"
WScript.Echo Err.Number & ": " & 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("d:x0e080003")
' Get the XML nodes that contain the individual HREFs.
Set oXMLHREFNodes = oXMLDoc.getElementsByTagName("a:href")
' Get the XML nodes that contain the individual HasSubs.
Set oXMLHasSubsNodes = oXMLDoc.getElementsByTagName("a:hassubs")
' 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 "Size: " & 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.