Monday, August 08, 2005

Iterating though storage groups with CDOEXM C# sample

Someone asked today about a C# sample for Iterating though mailboxes stores in a storage group in C#. There's a lack of good samples out there that show this at the moment so I threw one quickly together.

One thing that recently changed with the release of the latest Exchange SDK is that Microsoft has "removed support for CDOEXM in ASP and ASP.NET Web pages Because of issues with multiple-hop authentication and unexpected results observed in multithreaded runtime environments" see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/wss_sdk_whats_new.asp

I've put a downloadable copy of this code here


CDOEXM.IExchangeServer iExs;
CDOEXM.IStorageGroup iSg;
CDOEXM.MailboxStoreDB iMdb;
CDOEXM.PublicStoreDB iPf;
iExs = new CDOEXM.ExchangeServerClass();
iSg = new CDOEXM.StorageGroupClass();
iMdb = new CDOEXM.MailboxStoreDBClass();
iPf = new CDOEXM.PublicStoreDBClass();
string snServername = "servername";
iExs.DataSource.Open(snServername,null,ADODB.ConnectModeEnum.adModeReadWrite,
ADODB.RecordCreateOptionsEnum.adOpenIfExists,
ADODB.RecordOpenOptionsEnum.adOpenSource,null,null);
foreach (string Sgname in (IEnumerable)iExs.StorageGroups){
iSg.DataSource.Open(Sgname,null,ADODB.ConnectModeEnum.adModeReadWrite,
ADODB.RecordCreateOptionsEnum.adOpenIfExists,
ADODB.RecordOpenOptionsEnum.adOpenSource,null,null);
foreach( string Mbname in (IEnumerable)iSg.MailboxStoreDBs){
iMdb.DataSource.Open(Mbname,null,ADODB.ConnectModeEnum.adModeReadWrite,
ADODB.RecordCreateOptionsEnum.adOpenIfExists,
ADODB.RecordOpenOptionsEnum.adOpenSource,null,null);
System.Console.WriteLine("Store Name: " + iMdb.Name);
System.Console.WriteLine("Status: " + iMdb.Status);
System.Console.WriteLine("Storage Quota Limit: " + iMdb.StoreQuota);
System.Console.WriteLine("Over Quota Limit: " + iMdb.OverQuotaLimit);
System.Console.WriteLine("HardLimit: " + iMdb.HardLimit);
System.Console.WriteLine("");
}
foreach( string Pfname in (IEnumerable)iSg.PublicStoreDBs){
iPf.DataSource.Open(Pfname,null,ADODB.ConnectModeEnum.adModeReadWrite,
ADODB.RecordCreateOptionsEnum.adOpenIfExists,
ADODB.RecordOpenOptionsEnum.adOpenSource,null,null);
System.Console.WriteLine("Store Name: " + iPf.Name);
System.Console.WriteLine("Status: " + iPf.Status);
System.Console.WriteLine("");
}
}
}

10 comments:

Jason said...

Hello,
I've learned a lot from your different posts. This is what I'm trying to do.
Get the public folders out of each Exchange Server (that is visible through the Exchange System Manager). As the select * from exchange_PublicFolder only shows the folders at the highest level and not per storage group (code is partially commented) I'am now looking at the ADSI approach.

this is the code so far.
try
{
string cServername;
ManagementObjectCollection mcExchange=queryServer(".","select * from Exchange_Server");
txtNoOfServers.Text=mcExchange.Count.ToString();
//Double ttlSize=0;
foreach(ManagementObject moExchange in mcExchange)
{
cServername = moExchange["Name"].ToString();



string[] SQLArray=new string[7];

SQLArray[0]="select * from Exchange_Mailbox where size <=10240";
SQLArray[1]="select * from Exchange_Mailbox where size >" + 10240 + " and size <=" + 5*10240;
SQLArray[2]="select * from Exchange_Mailbox where size >" + 5*10240 + " and size <=" + 10*10240;
SQLArray[3]="select * from Exchange_Mailbox where size >" + 10*10240 + " and size <=" + 25*10240;
SQLArray[4]="select * from Exchange_Mailbox where size >" + 25*10240 + " and size <=" + 50*10240;
SQLArray[5]="select * from Exchange_Mailbox where size >" + 50*10240 + " and size <=" + 100*10240;
SQLArray[6]="select * from Exchange_Mailbox where size >" + 100*10240;
// number of mailboxes
txtMB.Text=queryServer(cServername,"select * from Exchange_Mailbox").Count.ToString();
//Mailbox sizes
int[] MBSizesArray= new int[7];
lstMBSizes.Items.Add(cServername);
for (int i=0;i<7;i++)
{
MBSizesArray[i]=queryServer(cServername,SQLArray[i]).Count;
lstMBSizes.Items.Add(MBSizesArray[i].ToString());
}
// //Number of Public folders according to Exchange
// txtPF.Text=queryServer(cServername,"select * from Exchange_PublicFolder").Count.ToString();
// //PF size
// SQLArray[0]="select * from Exchange_PublicFolder where totalmessagesize <=" + 10240;
// SQLArray[1]="select * from Exchange_PublicFolder where totalmessagesize >" + 10240 + " and totalmessagesize <=" + 5*10240;
// SQLArray[2]="select * from Exchange_PublicFolder where totalmessagesize >" + 5*10240 + " and totalmessagesize <=" + 10*10240;
// SQLArray[3]="select * from Exchange_PublicFolder where totalmessagesize >" + 10*10240 + " and totalmessagesize <=" + 25*10240;
// SQLArray[4]="select * from Exchange_PublicFolder where totalmessagesize >" + 25*10240 + " and totalmessagesize <=" + 50*10240;
// SQLArray[5]="select * from Exchange_PublicFolder where totalmessagesize >" + 50*10240 + " and totalmessagesize <=" + 100*10240;
// SQLArray[6]="select * from Exchange_PublicFolder where totalmessagesize >" + 100*10240;
// lstPFSizes.Items.Add(cServername);
// int[] PFSizesArray= new int[7];
// for (int i=0;i<7;i++)
// {
// PFSizesArray[i]=queryServer(cServername,SQLArray[i]).Count;
// lstPFSizes.Items.Add(PFSizesArray[i].ToString());
// }
//number of PF with AD
DirectoryEntry rootdse=new DirectoryEntry("LDAP://RootDSE");
DirectoryEntry cfg=new DirectoryEntry("LDAP://"+rootdse.Properties["configurationnamingcontext"].Value);
DirectorySearcher cfgsearch=new DirectorySearcher(cfg);
cfgsearch.Filter="(&(objectCategory=msExchExchangeServer)cn="+cServername +")";
cfgsearch.PropertiesToLoad.Add("distinguishedName");
cfgsearch.SearchScope=SearchScope.Subtree;
SearchResult res=cfgsearch.FindOne();
//define variables
SearchResultCollection resStorageGroups=searchContainer(res.Properties["distinguishedName"][0].ToString(),"&(objectCategory=msExchStorageGroup)");

//loop through the storagegroup collection
foreach (SearchResult sg in resStorageGroups)
{
SearchResultCollection resMailboxes=searchContainer(sg.Properties["distinguishedName"][0].ToString(),"&(objectCategory=msExchPrivateMDB)");
//loop through the mailbox collection
foreach(SearchResult mb in resMailboxes)
{


}

}



//messages to internet
DateTime startTime=new DateTime(System.DateTime.Now.Year,System.DateTime.Now.Month,System.DateTime.Now.Day-1);
DateTime endTime=startTime.AddHours(24);

string sTime=startTime.ToString("yyyyMMdd")+ "000000.000000+000";
string eTime=endTime.ToString("yyyyMMdd")+ "000000.000000+000";


ManagementObjectCollection mc=queryServer(cServername,"select * from Exchange_MessageTrackingEntry where Timelogged>='" + sTime + "' and TimeLogged<'" + eTime+"'");
txtMailVolumeMsg.Text=mc.Count.ToString();
Double ttlSize=0;
foreach(ManagementObject mo in mc)
{
ttlSize+=Convert.ToDouble(mo["Size"])/(1024*1024);
}
//size to internet
txtMailVolumeMB.Text=ttlSize.ToString();

//messages from internet


//size from internet


//#messages to internal recipient

//size to internal recipient
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}



}

private ManagementObjectCollection queryServer(string servername,string querystring)
{
try
{
System.Management.ConnectionOptions objconn = new System.Management.ConnectionOptions();
objconn.Impersonation = System.Management.ImpersonationLevel.Impersonate;
objconn.EnablePrivileges = true;
System.Management.ManagementScope exmangescope = new System.Management.ManagementScope(@"\\" + servername + @"\root\MicrosoftExchangeV2",objconn);
System.Management.ObjectQuery objquery = new System.Management.ObjectQuery(querystring);
System.Management.ManagementObjectSearcher objsearch = new System.Management.ManagementObjectSearcher(exmangescope,objquery);
return objsearch.Get();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
return null;
}
}

private SearchResultCollection searchContainer(string p,string fltr)
{
try
{
DirectoryEntry serverContainer=new DirectoryEntry("LDAP://"+p);
DirectorySearcher serverSearch=new DirectorySearcher(serverContainer);
serverSearch.Filter=fltr;
serverSearch.SearchScope=SearchScope.Subtree;
serverSearch.PropertiesToLoad.Add("cn");
serverSearch.PropertiesToLoad.Add("distinguishedName");
serverSearch.PropertiesToLoad.Add("homeMDBBL");
SearchResultCollection result=serverSearch.FindAll();

return result;
}
catch (Exception srcex)
{
MessageBox.Show(srcex.ToString());

}
}


msExchPrivateMDB is the name to select the mailbox data. I'm sure there must be one for public folders as well ?


Any help would be greatly appreciated.

Glen said...

The problem I can see with using ADSI is that this is only going to work if every public folder you want to report on is mail-enalbed. Also working out what storage groups or what instances there are of a public folder on a certain store isn't possible just using ADSI, replica information must be retrieved from the Exchange Store. The way i would do this is using WebDAV. Have a look at PFDAVAdmin which utilizes WebDAV to get all information about public folder. I've posted scripts before on working out instances use WebDAV.

Cheers
Glen

Jason said...

Hello Glen,

thanks for the reply. This means that the part for fetching the mailbox sizes can still be used (the data I receive seems to correspond to all the mailboxes in a certain server). I need to change the PF part to use WEBDAV instead of ADSI or WMI.
thanks again,

I'll check out your WEBDAV posts.
Jason

Anonymous said...

Thanks Glen!!! This is exactly what I've been looking for. I really appreciate you taking the time to post this!

Thanks again!

p capozzi said...

Thanks a lot. There is very little C# cdoexm code out there. This is a god send

Anup said...

Hi sir,

I have used for code for iterating through storage groups with CDOEXM C# example.

But i am unable to iterate through the mailboxes and than iterate through each of the folders of the mailboxes and than access the mails.

Kindly provide the code for the above as i had serached a lot on the NET ans also on the MSDN but i dint got a single example of c#.

I will be very thankfull to you if u will provide me the code or the steps to access the items of the folders.

Glen said...

I would suggest you look at using WebDAV to access the Mailbox content see http://blogs.msdn.com/webdav_101/archive/2008/03/12/howto-webdav-search-using-c.aspx

Anup said...

Hi sir,

I need to create a new mailBox (more than 1) and in that need to create folders in it using CDOEXM dll within Exchange server 2003 using C# .NET

Kindly help me out, how shall i proceed such that i can get the default storage group and the default mailbox store path (ie HomeMDB). Such that i can use CDOEXM.IMailBoxStore interface and create a new mailbox with mail enabled user.

Kindly provide me a good example or if possible some code steps such that i can follow it.

Thanks for helping me.

Glen said...

Have a read of http://blogs.msdn.com/mstehle/archive/2007/05/11/howto-using-cdoexm-in-asp-net-net-framework-2-0-walkthrough.aspx

Anup said...

Thanks a lot for your guidance sir,

As per the link provided by you helped me a lot to create a mailbox using CDOEXM in C#.

I have got stuck, as i need to create a folder in the mailbox and after creating a folder i need to create a mail or calender item or contact item manually.

Is there any API which may allow us to create a folder and items in the Exchange mailbox like CDOEXM ?

Kindly provide me an example which will allow me to create a folder and items in the folders.

Thanks for your great help.