Thursday, February 08, 2007

Exchange 2007 Mailbox Size Powershell Form Script

This script has been superseded by Version 5 this is a much better script that doesn't require EWS and also allows you see quota usage click here to goto version 5.

With the demise of the Exchange_Mailbox WMI class in Exchange 2007 the new method of getting Mailbox sizes on Exchange 2007 has moved into the Exchange Management Shell via the new get-mailboxstatistics cmdlet. Mailbox sizes in themselves while useful can’t tell you where the space in a particular mailbox is being used. This is where you need to be able to drill down into the mailbox folders themselves and see where a user in particular is using their space eg(inbox, sent items etc). So I’ve put together a powershell script that can do just that it creates a winform that allows you to select what server you want to report on. Then it will run the get-mailboxstatistics cmdlet to retrieve all mailbox sizes for all users on this server you select and populate a ListView with these values. An event is wired to the ListView rows so when you select a row in this ListView (eg a mailbox you want to know where the space is being use). Another function runs that then performs a FindFolder operation via Exchange Web Services on the selected user which will retrieve a list of every folder in the mailbox and the size of that folder. This data is used to populate a datatable which is then used to populate another list view object that will display the names and sizes of those folders in the mailbox. To keep with the hierarchal nature of a mailbox the folder size listview first shows all the root folders and the sizes displayed are the sums of the size of the root folders plus the size of any child folders within those root folder. To see what the child folder sizes are if you click the row in the second listview for the corresponding folder another function will fire that will clear the listview and then redisplay the data for the child folder with summed totals for all these folders. To go back up one folder a back button will appear at the top of the second ListView that allows back navigation. This second operation doesn’t cause the Server to be re-queried it just uses the same data from the datatable and presents it in a different format.

To access the folders within a mailbox the EWS code relies on Impersonation to be configured the Exchange SDK has details on how to give an account Impersonation rights it involves granting two rights the first is on the Server which allows a user to submit impersonation calls and the second is either on the user account you wish to access itself or the Mailbox database if you wanted to access all mailboxes within a particular mail store for this script you want to grant the latter permission on all stores that you want to be able to get the mailbox folder sizes from. For details of how to do this see. Once you have setup impersonation you then need to configure the code with the details of the user you have setup to allow impersonation. In line 3 there are the following 4 lines that affect this.

$unUserName = "username"
$psPassword = "password$"
$dnDomainName = "domain"
$cdUsrCredentials = new-object System.Net.NetworkCredential($unUserName , $psPassword , $dnDomainName)

If you instead want to use NTLM authentication from the user that is running the script so you don’t have hard code the username and password if you comment (or delete) the lines above in the script and change the following line (124) from

$WDRequest.Credentials = $cdUsrCredentials

To

$WDRequest.UseDefaultCredentials = $True

This will mean the code will run the EWS Findfolder operation under the security context of the user executing the script. The error’s you receive if you get access denied aren’t very descriptive you usually just get a 501 error so be wary or this.

With the EWS code because it runs across SSL you need to make sure that browser trusts the certificate that’s being used (eg the code cant deal with SSL certificate errors) this is usually just a matter of importing the certificate from OWA so its trusted if you not using a registered certificate. (You’ll know what I mean if you get an error about SSL when you try to run the EWS code).

The script actually makes use of 2 Exchange cmdlet’s the first is get-mailboxstatitics and then get-user is used to get the SID of the user in question. The SID is used as part of the impersonation header within the EWS code. Because of this reliance on the Exchange cmdlet’s the script needs to be run from within the Exchange Management Shell.

I’ve put a downloadable copy of the script here the code itself looks like

[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")

$unUserName = "username"
$psPassword = "password$"
$dnDomainName = "domain"
$cdUsrCredentials = new-object System.Net.NetworkCredential($unUserName , $psPassword
, $dnDomainName)

function getMailboxSizes(){

$lbListView.clear()
$lbListView.Columns.Add("UserName",150)
$lbListView.Columns.Add("# Items",70)
$lbListView.Columns.Add("MB Size(MB)",80)
$lbListView.Columns.Add("DelItems (KB)",90)

get-mailboxstatistics -Server $snServerNameDrop.SelectedItem.ToString()
ForEach-Object{
$item1 = new-object System.Windows.Forms.ListViewItem($_.DisplayName)
$item1.SubItems.Add($_.ItemCount)
$item1.SubItems.Add($_.TotalItemSize.Value.ToMB() )
$item1.SubItems.Add($_.TotalDeletedItemSize.Value.ToKB())

$lbListView.items.add($item1)
}

$form.Controls.Add($lbListView)
}

function enumFolderSizes($fsFolderIDtoSearch){
$private:enfsFilterString = "ParentID = '" + $fsFolderIDtoSearch + "'"
$private:enSubFolders = $fsTable.select($enfsFilterString)
for($fcount1 = 0;$fcount1 -le $enSubFolders.GetUpperBound(0); $fcount1++){
$global:fldSize = $global:fldSize + $enSubFolders[$fcount1][3]
$global:itemCount = $global:itemCount + $enSubFolders[$fcount1][5]
if ($enSubFolders[$fcount1][4] -ne 0){
enumFolderSizes($enSubFolders[$fcount1][1])
}

}
}

function BackFolder(){
$private:bfFilterString = "FolderID = '" + $global:LastFolder + "'"
$private:bfFolder = $fsTable.select($bfFilterString)
GetSubFolderSizes($bfFolder[0][2])

}

function GetSubFolderSizes($fiFIDToSearch){
$global:LastFolder = $fiFIDToSearch
$upButton.visible = $true
$lbFldListView.clear()
$lbFldListView.Columns.Add("Folder Name",150)
$lbFldListView.Columns.Add("# Items",80)
$lbFldListView.Columns.Add("Size(MB)",80)
$lbFldListView.Columns.Add("Has Sub",80)
$lbFldListView.Columns.Add("FID",0)
$subfsFilterString = "ParentID = '" + $fiFIDToSearch + "'"
$subFolders = $fstable.select($subfsFilterString)
for($fcount2 = 0;$fcount2 -le $subFolders.GetUpperBound(0); $fcount2++){
$global:fldSize = $subFolders[$fcount2][3]
$global:itemCount = $subFolders[$fcount2][5]
if ($subFolders[$fcount2][4] -ne 0){
enumFolderSizes($subFolders[$fcount2][1])
}
$item1 = new-object System.Windows.Forms.ListViewItem($subFolders[$fcount2][0])
$item1.SubItems.Add($global:itemCount)
$item1.SubItems.Add([math]::round(($fldsize/1mb),2))
if ($subFolders[$fcount2][4] -ne 0){
$item1.SubItems.Add("Yes")
}
else {
$item1.SubItems.Add("No")
}
$item1.SubItems.Add($subFolders[$fcount2][1])
$lbFldListView.items.add($item1)
}


}


function GetFolderSizes($siSIDToSearch){
$fsTable.clear()
$lbFldListView.clear()
$lbFldListView.Columns.Add("Folder Name",150)
$lbFldListView.Columns.Add("# Items",80)
$lbFldListView.Columns.Add("Size(MB)",80)
$lbFldListView.Columns.Add("Has Sub",80)
$lbFldListView.Columns.Add("FID",0)
$snServername = $snServerNameDrop.SelectedItem.ToString()
$siSIDToSearch = get-user $siSIDToSearch

$smSoapMessage = "<?xml version='1.0' encoding='utf-8'?>" `
+ "<soap:Envelope xmlns:soap=`"http://schemas.xmlsoap.org/soap/envelope/`" " `
+ " xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`"
xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`"" `
+ " xmlns:t=`"http://schemas.microsoft.com/exchange/services/2006/types`" >" `
+ "<soap:Header>" `
+ "<t:ExchangeImpersonation>" `
+ "<t:ConnectingSID>" `
+ "<t:SID>" + $siSIDToSearch.SID + "</t:SID>" `
+ "</t:ConnectingSID>" `
+ "</t:ExchangeImpersonation>" `
+ "</soap:Header>" `
+ "<soap:Body>" `
+ "<FindFolder
xmlns=`"http://schemas.microsoft.com/exchange/services/2006/messages`" " `
+ "xmlns:t=`"http://schemas.microsoft.com/exchange/services/2006/types`"
Traversal=`"Deep`"> " `
+ "<FolderShape>" `
+ "<t:BaseShape>AllProperties</t:BaseShape>" `
+ "<AdditionalProperties
xmlns=""http://schemas.microsoft.com/exchange/services/2006/types"">" `
+ "<ExtendedFieldURI PropertyTag=""0x0e08"" PropertyType=""Integer"" />" `
+ "</AdditionalProperties>" `
+ "</FolderShape>" `
+ "<ParentFolderIds>" `
+ "<t:DistinguishedFolderId Id=`"root`"/>" `
+ "</ParentFolderIds>" `
+ "</FindFolder>" `
+ "</soap:Body></soap:Envelope>"

$strRootURI = "https://" + $snServername + "/ews/Exchange.asmx"
$WDRequest = [System.Net.WebRequest]::Create($strRootURI)
$WDRequest.ContentType = "text/xml"
$WDRequest.Headers.Add("Translate", "F")
$WDRequest.Method = "Post"
$WDRequest.Credentials = $cdUsrCredentials
$bytes = [System.Text.Encoding]::UTF8.GetBytes($smSoapMessage)
$WDRequest.ContentLength = $bytes.Length
$RequestStream = $WDRequest.GetRequestStream()
$RequestStream.Write($bytes, 0, $bytes.Length)
$RequestStream.Close()
$WDResponse = $WDRequest.GetResponse()
$ResponseStream = $WDResponse.GetResponseStream()
$ResponseXmlDoc = new-object System.Xml.XmlDocument
$ResponseXmlDoc.Load($ResponseStream)
$DisplayNameNodes = @($ResponseXmlDoc.getElementsByTagName("t:DisplayName"))
$ExtenedPropertyField = @($ResponseXmlDoc.getElementsByTagName("t:Value"))
$FolderIdNodes = @($ResponseXmlDoc.getElementsByTagName("t:FolderId"))
$ParentFolderIdNodes =
@($ResponseXmlDoc.getElementsByTagName("t:ParentFolderId"))
$ChildFolderCountNodes =
@($ResponseXmlDoc.getElementsByTagName("t:ChildFolderCount"))
$TotalItemCountNodes = @($ResponseXmlDoc.getElementsByTagName("t:TotalCount"))
for($i=0;$i -lt $DisplayNameNodes.Count;$i++){
if ($DisplayNameNodes[$i].'#text' -eq "Top of Information Store"){$rootFolderID
= $FolderIdNodes[$i].GetAttributeNode("Id").'#text'}
$fiFolderID = $FolderIdNodes[$i].GetAttributeNode("Id")
$pfParentFolderID = $ParentFolderIdNodes[$i].GetAttributeNode("Id")
$fsTable.Rows.Add($DisplayNameNodes[$i].'#text',$fiFolderID.'#text',$pfParentFolderID.'#text',$ExtenedPropertyField[$i].'#text',$ChildFolderCountNodes[$i].'#text',$TotalItemCountNodes[$i].'#text')
}
$fsFilterString = "ParentID = '" + $rootFolderID + "'"
$rrRootFolders = $fstable.select($fsFilterString)
for($fcount = 0;$fcount -le $rrRootFolders.GetUpperBound(0); $fcount++){
if ($rrRootFolders[$fcount][0] -ne "Top of Information Store"){
$global:fldSize = $rrRootFolders[$fcount][3]
$global:itemCount = $rrRootFolders[$fcount][5]
if ($rrRootFolders[$fcount][4] -ne 0){
enumFolderSizes($rrRootFolders[$fcount][1])
}
$item1 = new-object
System.Windows.Forms.ListViewItem($rrRootFolders[$fcount][0])
$item1.SubItems.Add($global:itemCount)
$item1.SubItems.Add([math]::round(($fldsize/1mb),2))
if ($rrRootFolders[$fcount][4] -ne 0){
$item1.SubItems.Add("Yes")
}
else {
$item1.SubItems.Add("No")
}
$item1.SubItems.Add($rrRootFolders[$fcount][1])
$lbFldListView.items.add($item1)
}
}

$form.Controls.Add($lbFldListView)
}
$form = new-object System.Windows.Forms.form
$global:LastFolder = ""
# Add DataTable

$Dataset = New-Object System.Data.DataSet
$fsTable = New-Object System.Data.DataTable
$fsTable.TableName = "Folder Sizes"
$fsTable.Columns.Add("DisplayName")
$fsTable.Columns.Add("FolderID")
$fsTable.Columns.Add("ParentID")
$fsTable.Columns.Add("Size)",[int])
$fsTable.Columns.Add("ChildFolderCount",[int])
$fsTable.Columns.Add("TotalCount",[int])
$Dataset.tables.add($fsTable)

# Add Server DropLable
$snServerNamelableBox = new-object System.Windows.Forms.Label
$snServerNamelableBox.Location = new-object System.Drawing.Size(10,20)
$snServerNamelableBox.size = new-object System.Drawing.Size(100,20)
$snServerNamelableBox.Text = "ServerName"
$form.Controls.Add($snServerNamelableBox)

# Add Server Drop Down
$snServerNameDrop = new-object System.Windows.Forms.ComboBox
$snServerNameDrop.Location = new-object System.Drawing.Size(130,20)
$snServerNameDrop.Size = new-object System.Drawing.Size(130,30)
get-mailboxserver ForEach-Object{$snServerNameDrop.Items.Add($_.Name)}
$snServerNameDrop.Add_SelectedValueChanged({getMailboxSizes})
$form.Controls.Add($snServerNameDrop)

# Add List Box to DisplayMailboxs


$lbListView = new-object System.Windows.Forms.ListView
$lbListView.Location = new-object System.Drawing.Size(10,50)
$lbListView.size = new-object System.Drawing.Size(400,500)
$lbListView.LabelEdit = $True
$lbListView.AllowColumnReorder = $True
$lbListView.CheckBoxes = $False
$lbListView.FullRowSelect = $True
$lbListView.GridLines = $True
$lbListView.View = "Details"
$lbListView.Sorting = "Ascending"
$lbListView.add_click({GetFolderSizes($this.SelectedItems.item(0).text)});


# Add List Box to Display FolderSizes


$lbFldListView = new-object System.Windows.Forms.ListView
$lbFldListView.Location = new-object System.Drawing.Size(500,50)
$lbFldListView.size = new-object System.Drawing.Size(400,500)
$lbFldListView.LabelEdit = $True
$lbFldListView.AllowColumnReorder = $True
$lbFldListView.FullRowSelect = $True
$lbFldListView.GridLines = $True
$lbFldListView.View = "Details"
$lbFldListView.Sorting = "Ascending"
$lbFldListView.add_click({GetSubFolderSizes($this.SelectedItems.item(0).subitems[4].text)});


# UP folder Button

$upButton = new-object System.Windows.Forms.Button
$upButton.Location = new-object System.Drawing.Size(500,19)
$upButton.Size = new-object System.Drawing.Size(120,23)
$upButton.Text = "Back Folder level"
$upButton.visible = $false
$upButton.Add_Click({BackFolder})
$form.Controls.Add($upButton)

$form.Text = "Exchange 2007 Mailbox Size Form"
$form.size = new-object System.Drawing.Size(1000,600)
$form.autoscroll = $true
$form.topmost = $true
$form.Add_Shown({$form.Activate()})
$form.ShowDialog()

41 comments:

Anonymous said...

Great script. I suggest adding a sort to mailbox size or number of items.

Anonymous said...

Very cool. Do you have a version of this for vbscript?

Glen said...

Because im using Exchange CMDlets to get the mailbox sizes you can use VBS you need to use Exchange Management shell. The WebServices query can be done from VBS but there are no winforms with VBS so you would have to rewrite it as maybe a html forms. My advice is to install powershell once you have started using it you will never look back. (you'll still see plenty of VBS here though)

Cheers
Glen

Anonymous said...

OK - I am a rookie at this and was trying to do the XML post you described (i.e., report on the mailbox sizes of our users) from a pure ASP page using XMLHTTP. Is this possible - or can I not access the mailbox sizes from an ASP page?

Anonymous said...

When I tried the XML for this page from an ASP page, I get a 403 Forbidden error response. I believe that all of the impersonation permissions are set up correctly.

Glen said...

Does this work in powershell for you using the script ?. 403 errors aren't usually related to permissions it usually more to do with the code you are using eg you trying to post to the wrong URL etc.

Are you using Exchange 2007 the code that does an XML post is only retriving the individual folder sizes for a selected user the code that get all the mailbox size is the Exchange 2007 cmdlet get-mailboxstatistics.

Cheers
Glen

Anonymous said...

Glen: a bit off topic, but you are the foremost EX07 expert I can find. I had a wsh script which reads a mailbox, lists the emails in it, uploads any attachments into an SQL database and then deletes the message. This worked fine in EX03, but not since we upgraded to EX07 (even though the x-ms-enumatts method returns a url to the attachments of an email, a subsequent GET xmlhttp request to the returned url returns a 403 Forbidden error. Any thoughts? All appropriate permissions appear to be in place. Thank you for your assistance and your continued very helpful blogs on Exchange 2007.

Glen said...

On Exchange 2007 the Get verbs works a lot differently. Eg you can nolonger do a Get on a DAV:href in 2007. (as far as i know i know other people have tried and said they have recieved a simular errors but i have not seen anything offical on this). My suggestion is if you have gone Exchange 2007 then use EWS. The other way is you could sniff what OWA is doing and try to reproduce this in a WebDAV get for me when i download an attachment in OWA the GET request look like

ET /owa/attachment.ashx?attach=1&id=RgAAAAD4jtVG6ykFSr70M3B42mLNBwDyr5m1GceISqNNjoABUQIhAAAAABRlAADyr5m1GceISqNNjoABUQIhAAAAABq9AAAJ&attid0=EADyKXjOofgVTpkIS893EWAn&attcnt=1

The first ID relates to the message itself which you can constructed from the EntryID of the message The AttachID (not really sure). If you can go EWS life should be eaiser.

Cheers
Glen


Cheers
Glen

Anonymous said...

Nice script. Is there a way to export this information out easily, so it can be sorted by mailbox size etc?

Glen said...

The easiest way to export the mailbox sizes to a csv file is just to run something like this from the EMS

Get-MailboxStatistics -Database "mailbox database" | Sort @{expression="totalitemsize";descending=$true} | select DisplayName, @{expression={$_.totalitemsize.value.ToMB()}}, itemcount, lastlogontime, lastlogofftime,lastloggedonuseraccount | Export-csv c:\mbreport.csv

Anonymous said...

Glen,

Thanks for all your hard work. I'm having an issue with this script though. I've setup the impersonation with a user and have the script setup with those credentials. The main window shows sizes ok but when I try to drill down, I get the errors below (and I apologize for the long post). Is there anything you would suggest?


Exception calling "GetRequestStream" with "0" argument(s): "Unable to connect t
o the remote server"
At C:\ExchangeScripts\mbsizereportv1.ps1:123 char:45
+ $RequestStream = $WDRequest.GetRequestStream( <<<< )
You cannot call a method on a null-valued expression.
At C:\ExchangeScripts\mbsizereportv1.ps1:124 char:21
+ $RequestStream.Write( <<<< $bytes, 0, $bytes.Length)
You cannot call a method on a null-valued expression.
At C:\ExchangeScripts\mbsizereportv1.ps1:125 char:21
+ $RequestStream.Close( <<<< )
Exception calling "GetResponse" with "0" argument(s): "Unable to connect to the
remote server"
At C:\ExchangeScripts\mbsizereportv1.ps1:126 char:37
+ $WDResponse = $WDRequest.GetResponse( <<<< )
You cannot call a method on a null-valued expression.
At C:\ExchangeScripts\mbsizereportv1.ps1:127 char:48
+ $ResponseStream = $WDResponse.GetResponseStream( <<<< )
Exception calling "Load" with "1" argument(s): "The URL cannot be empty.
Parameter name: url"
At C:\ExchangeScripts\mbsizereportv1.ps1:129 char:21
+ $ResponseXmlDoc.Load( <<<< $ResponseStream)

Glen said...

If you are using a default install one of things that can cause this script to fail is the Self Signed Certificate that is used by default. If you haven't imported this certificate into the machines local store so its trusted on the machine that is issuing the query this can cause the script to fail. Eg when you go into OWA on the server do you get certificate prompt/error if so import the OWA certificate to the local store and this should fix the problem. This script can't deal with the prompts so its needs this certificate to be trusted.

Cheers
Glen

Anonymous said...

I'm pretty sure I have the certificates setup correctly on my client access server. The certificates show up in the certificate store for the computer as well. Is there anything else I should check for the the above errors?

Anonymous said...

Glen,

It looks like I've found the offending line for me:

$strRootURI = "https://" + $snServername + "/ews/Exchange.asmx"

I changed that to the exact URL for our client access server and the script now works, but only from a mailbox serve, not from another machine on the network.

Do you think we have something setup icorrectly for our AS service URL or otherwise? The mailbox servers themselves do not have these folders, so I'm concerned we have a potential issue. Thanks.

Glen said...

Ahh i see thanks for that you've pointed out a major flaw with this script. Most of the systems i work on because of cost constraints don't split the different roles so my CAS and mailbox roles are combined. But if you have you roles split then the method I've used to get the servername doesn't work . In this case you need to use Autodiscover to find the correct EWS url to use. So i need to come up with another version of this script that uses Autodiscover. Okay Version 2 comming soon.

Cheers
Glen

Anonymous said...

It's absurd that Exchange doesn't let you get this information through a simple Console report. How is it that Exchange gets harder to manage and less reliable with each version?

Anonymous said...

Your link to MSDN site with how to configure impersonation is down. Can you please re-do the link or include instructions? Thanks.

Glen said...

Okay that should be fixed the link is http://msdn2.microsoft.com/en-us/library/bb204095.aspx

Ivan said...

How do I view the size of each users mailbox in Exchange2007 ?

Glen said...

You cant get it through the Exchange Management console you need to use the Exchange Management Shell get-mailboxstatitics cmdlet

Cheers
Glen

Anonymous said...

From following the link to setting up impersonation, I'm hoping someone can clarify:

To be able to run this script on potentially any mailbox, I'd need to set up an account with impersonation permissions individually to every user mailbox account?

Anonymous said...

Ah, nvm. I see you can set it at the db/server level.

Wren said...

Hi Glen,

I am facing a problem when a attendee accept a meetingrequest .The organiser gets a response mail but problem is I am not getting the fields Location and When from the any of meeting response objects that are recieved by the mailbox.And these fields are required in the Showing the details.Please help me

Glen said...

Hi Wren,

Its hard to say what going wrong you need to do some tracing with a mapi editor like Outlook Spy or MFCmapi. How are you submitting the meeting request.

Cheers
Glen

Wren said...

Hi Glen,
Meetingrequest object is sent by the organiser by creating the CalenderItenm object and setting the attendees field via CreateItem function of EWS.I am sending the response by creating AcceptItem/DeclineItem etc type and putting its ReferenceItemId from meetingrequest ItemID and then sending through CreateItem.Then the Organiser gets the MeetingResponseType Object which doesn't contain the property like When and Location which is needed.

Thanks

Glen said...

This is where you need to start doing some tracking with a Mapi editor. You need to looking at each object the Send Request and the response and see where the information is going missing (if it is). If you can see the information with a Mapi editor but not via EWS it might just be a matter of tweaking your code a bit. I know the code I've tested before im pretty sure it did work.

Wren said...

Hi Glen,
I want to provide the Calendar Delegation in my application.Can you please put some light on this(any link,sample etc..).As I am new to EWS
Thanks

Glen said...

Its possible using SP1 with EWS i may have a sample some where i'll get back to you can't say I've seen anything online.

Cheers
Glen

Wren said...

Hi Glen,

I am setting extended property in MessageType and also set the propery for DeliveryReciept/ReadReciept.When I get the mail for Delivery/ReadReciept for the corresponding mail I didn't get the Extended property here that I set.Similarly I am setting the extended propery in a CalendarItem object I didn't get the same in any of object like MeetingRequestType,MeetingResponseType etc .I want that extended property in all objects that are automatically created by EWS.

Thanks

Matthew said...

I could use a little assistance with this one. I understand where the problem is but not how to resolve it. When the script queries the server for the folder drill-down it's trying to connect to the servername.internaldomain.local/...
In my case my cert on this server is for mail.publicdomain.com and if in IE you go to the servername.internaldomain.local IE gives a cert warning of course. I've tried changing the script (at approximately line 133) to connect directly to my external domain name but that presents an authentication error. Going to internal it generates an SSL error. Any help on this one would be fantastic!

Glen said...

Use Version 4 it no-longer uses EWS to get Foldersizes but uses the Get-MailboxFolderStatistics cmdlet which only requires that you have deletegate Exchange Admin rights. It also has a bunch of fixes and other functionality. http://gsexdev.blogspot.com/2008/02/version-4-of-mailbox-size-gui-and-using.html

Chris said...

could this script be modified as to select the storage group and/or even a database for a perticular server?

right now I have a number of companies for which I provide mailservices

whenever I export the results I need to filter by company (so actually by storage group and/or database)
good thing I know who works for whom ;-)

Glen said...

Yes you can change the get-mailbox and get-mailboxstatistics cmdlets to filter by database. With storage Group you would need to do the filter yourself but all you really need is a few if statments to do the filtering. Make sure you use the lastest version of the script version 5 which is linked at the top of post

Cheers
Glen

Chris said...

is there a way you could provide this functionality in the GUI with the use of dropdown lists?
that would be sweet ;-)

Glen said...

Maybe its not a 5 minute task i'll add it to the list and see what i can do.

Cheers
Glen

Anonymous said...

Hi, Is it possible to run this script from a pc having powershell but is different thant the one where exchange is installed? I mean a separate pc than exchange but can access the machine with exchange using internet?

Glen said...

The script requires the Exchanage Managenet Shell to be installed and as long as the workstation is a member of the domain and can run EMS cmdlets and the user logged on has delegated Exchange Admin rights it will work fine on a workstation.

Cheers
Glen

Anonymous said...

Hi Glen,

is it not possible at all to write an application (eg. vb.net) which can get mailbox sizes from different exchange 2007 orgs?
I am rewriting an application that did the trick in 2003 with a single user using trust authentication

Glen said...

Just Invoke the EMS cmdlets from .NET see http://blogs.msdn.com/mstehle/archive/2007/01/25/outbox-introduction-to-exchange-powershell-automation-part-2.aspx

Cheers
Glen

Anonymous said...

Great Script! I do have a question about the MB Size vs. DelItems.

I have (1) mailbox that claims to have 4.90 GB in it and Outlook reports the same. However, the delitems reports 7.32 GB and Outlook only reports 530MB. Any ideas why the descrepancy?

Glen said...

Are you using Exchange 2010 ? with the dumpster 2.0 how deleted items are held with in the mailbox is very different to previous versions of Exchange eg the recovereddeletedItems folder is under the nonipmsubtree so it not appear in traditional reports.
Cheers
Glen