How can I get list of all available calendars in Outlook?
I have two users logged in, and I can find them with this code:
Outlook.NameSpace session = Globals.ThisAddIn.Application.Session;
Outlook.Accounts accounts = session.Accounts;
Outlook.Account account = null;
List<string> accountList = new List<string>();
for (int i = 1; i <= accounts.Count; i++)
{
account = accounts[i];
if (account != null)
accountList.Add(account.DisplayName);
}
How can I now get list of calendars per user? Or at least get list of all calendars mixed together?
You can use next code for solve this problem:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Outlook.NameSpace session = Globals.ThisAddIn.Application.Session;
Outlook.Accounts accounts = session.Accounts;
List<Outlook.MAPIFolder> calendars = new List<Outlook.MAPIFolder>();
foreach (Outlook.Account account in accounts)
{
Outlook.Recipient recipient = session.CreateRecipient(account.DisplayName);
Outlook.MAPIFolder calendar = session.GetSharedDefaultFolder(recipient, Outlook.OlDefaultFolders.olFolderCalendar);
if (calendar != null)
{
calendars.Add(calendar);
}
}
}
The strategy of the suggested answer works quite well. I tried a similar solution to get the correct calendar for a specific user, like this:
var session = Application.Session;
var accounts = session.Accounts;
//get default calendar
var calendar = (MSOutlook.Folder)session.GetDefaultFolder(MSOutlook.OlDefaultFolders.olFolderCalendar);
//get calendar for specific user
foreach (MSOutlook.Account account in accounts)
{
if (string.Equals(account.SmtpAddress, "someone#somewhere.com", StringComparison.InvariantCultureIgnoreCase))
{
var recipient = session.CreateRecipient(account.DisplayName);
calendar = (MSOutlook.Folder)session.GetSharedDefaultFolder(recipient,
MSOutlook.OlDefaultFolders.olFolderCalendar);
break;
}
}
Marshal.ReleaseComObject(session);
Marshal.ReleaseComObject(accounts);
Related
Update:
For me, LDAP way only worked for finding email addresses inside AD groups, for eg: named ITSolutionDeliveryDevelopers group. NOT inside Exchange Distribution Lists, for eg: named abc#domainname.com.
// I was able to figure out entry as suggested by #Gabriel Luci and
// all of the following possible formats worked for me:
// ngroupnet.com is my company domain name.
var entry = new DirectoryEntry();
var entry = new DirectoryEntry("LDAP://ngroupnet.com");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyAccountUsername", "MyAccountPassword");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyName#mycompany.com", "MyEmailAccountPassword");
For my complete answer, take a look below: https://stackoverflow.com/a/71518937/8644294
Original Question:
What is the best way to get all the individual email addresses comprising an exchange distribution list?
For eg: I have this distribution list called abc#domainname.com that has email addresses:
a#domainname.com
b#domainname.com
c#domainname.com
Now I need to get these addresses using C# code.
I found solution using LDAP but I felt it'd be a hassle to figure out LDAP path to my Active Directory.
// How do I get this LDAP Path, username and password?
// Is the username and password service account credentials of the app?
// And do they need to be registered in AD?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
LDAP Way:
public static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
var result = new List<string>();
try
{
// How do I get this LDAP Path?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
var search = new DirectorySearcher(entry);
search.Filter = $"CN={dlName}";
int i = search.Filter.Length;
string str = "", str1 = "";
foreach (SearchResult AdObj in search.FindAll())
{
foreach (String objName in AdObj.GetDirectoryEntry().Properties["member"])
{
str += Convert.ToString(objName) + "<Br>";
int selIndex = objName.IndexOf("CN=") + 3;
int selEnd = objName.IndexOf(",OU") - 3;
str1 += objName.Substring(selIndex, selEnd).Replace("\\", "");
DirectorySearcher dsSearch = new DirectorySearcher(entry);
dsSearch.Filter = "CN=" + objName.Substring(selIndex, selEnd).Replace("\\", "");
foreach (SearchResult rs in dsSearch.FindAll())
{
//str1 += "<p align='right'><font face='calibri' color='#2266aa' size=2>" + Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["displayName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["sAMAccountName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["department"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["memberOf"].Value) + "</font></p>";
str1 = Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value);
result.Add(str1);
}
}
}
return result;
}
catch (Exception ex)
{
//Do some logging or what have you.
throw;
}
}
So I just went with the EWS route.
EWS Way:
public static static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
try
{
var service = new ExchangeService();
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
service.Credentials = cred;
service.Url = new Uri("https://outlook.office365.com/ews/exchange.asmx");
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
var expandedEmailAddresses = new List<string>();
ExpandGroupResults myGroupMembers = service.ExpandGroup(dlName);
foreach (EmailAddress address in myGroupMembers.Members)
{
expandedEmailAddresses.Add(address.Address);
}
return expandedEmailAddresses;
}
catch (Exception ex)
{
// The DL doesn't have any members. Handle it how you want.
// Handle/ Log other errors.
}
}
Is EWS approach a good way?
If Yes, then I'm good. If not, I'll have to figure out that LDAP path.
Or if there's even a better way, please let me know.
If the computer you run this from is joined to the same domain as the group you're looking for, then you don't need to figure out the LDAP path. You can just do:
var search = new DirectorySearcher();
If your computer is not joined to the same domain, then you just use the domain name:
var entry = new DirectoryEntry("LDAP://domainname.com");
This requires that there is no firewall blocking port 389 between your computer and the domain controller(s). If you need to pass credentials, then do that:
var entry = new DirectoryEntry("LDAP://domainname.com", username, password);
The credentials can be any user on the domain.
That said, there are a lot of inefficiencies in your code that will make it run much slower than needed. I wrote an article about this that can help you update your code: Active Directory: Better Performance
Is EWS approach a good way?
If it works, it works. I'm not an expert on EWS (although I have used it), but I'm fairly certain that's using Basic Authentication, which is going to be disabled in October.
If all the Mailboxes are on Office365 then i would suggest you use the Graph API instead eg https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=http . There are several advantage in terms of security eg you could use Application permissions and all you need is access to the directory while if you did the same thing in EWS it would require full access to at least one mailbox.
LDAP will be best performing of the 3 if ultimate speed in the only thing that is important.
My complete solution for future reference. :)
EWS Way - For expanding Exchange Distribution Lists
public class SomeHelper
{
private static ExchangeService _exchangeService = null;
public static async Task<HashSet<string>> GetExchangeDistributionListMembersAsync(IEnumerable<string> dlNames)
{
var allEmailAddresses = new HashSet<string>();
foreach (var dlName in dlNames)
{
if (!SomeCache.TryGetCachedItem(dlName, out var dlMembers))
{
var groupEmailAddresses = new List<string>();
var exchangeService = await GetExchangeServiceAsync();
try
{
var myGroupMembers = exchangeService.ExpandGroup(dlName);
// Add the group members.
foreach (var address in myGroupMembers.Members)
{
groupEmailAddresses.Add(address.Address);
}
}
catch (Exception ex)
{
//If it can't expand the dlName, just return it.
groupEmailAddresses.Add(dlName);
//groupEmailAddresses.Add($"Attempting to expand '{dlName}' resulted in error message: '{ex.Message}'.");
}
// Cache the groupEmailAddresses for 7 days.
// Because Distribution Lists rarely change and expanding DL is an expensive operation.- AshishK Notes
SomeCache.AddItemToCache(dlName, groupEmailAddresses, 10080);
allEmailAddresses.UnionWith(groupEmailAddresses);
}
else
{
allEmailAddresses.UnionWith((List<string>)dlMembers);
}
}
return allEmailAddresses;
}
private static async Task<ExchangeService> GetExchangeServiceAsync()
{
if (_exchangeService == null)
{
_exchangeService = new ExchangeService();
var exchangeUrl = "https://outlook.office365.com/ews/exchange.asmx";
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
_exchangeService.Credentials = cred;
//_exchangeService.AutodiscoverUrl("sharedmailbox#domain.com");
_exchangeService.Url = new Uri(exchangeUrl);
_exchangeService.TraceEnabled = true;
_exchangeService.TraceFlags = TraceFlags.All;
return _exchangeService;
}
else
{
return _exchangeService;
}
}
}
public class SomeCache
{
private static readonly ObjectCache _cache = MemoryCache.Default;
public static void AddItemToCache(string key, object itemToAdd, int cacheDurationMinutes)
{
var _policy = new CacheItemPolicy
{
Priority = CacheItemPriority.Default,
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(cacheDurationMinutes)
};
_cache.Set(key, itemToAdd, _policy);
}
public static bool TryGetCachedItem(string key, out object cachedObject)
{
try
{
cachedObject = _cache[key] as object;
}
catch (Exception ex)
{
cachedObject = null;
}
return !(cachedObject == null);
}
}
LDAP Way - For expanding Active Directory Groups
public static List<string> GetADGroupDistributionListMembers(string adGroupName)
{
var returnResult = new List<string>();
var entry = GetDirectoryEntry();
DirectorySearcher groupSearch = new DirectorySearcher(entry)
{
Filter = "(SAMAccountName=" + adGroupName + ")"
};
groupSearch.PropertiesToLoad.Add("member");
SearchResult groupResult = groupSearch.FindOne(); // getting members who belong to the adGroupName
if (groupResult != null)
{
for (int iSearchLoop = 0; iSearchLoop < groupResult.Properties["member"].Count; iSearchLoop++)
{
string userName = groupResult.Properties["member"][iSearchLoop].ToString();
int index = userName.IndexOf(',');
userName = userName.Substring(0, index).Replace("CN=", "").ToString(); // the name of the user will be fetched.
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(name=" + userName + ")"
};
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne(); //finding the mail id
if (result != null)
{
returnResult.Add(result.Properties["mail"][0].ToString());
}
}
}
return returnResult;
}
public static DirectoryEntry GetDirectoryEntry()
{
DirectoryEntry entryRoot = new DirectoryEntry("LDAP://RootDSE");
string Domain = (string)entryRoot.Properties["defaultNamingContext"][0];
DirectoryEntry de = new DirectoryEntry
{
Path = "LDAP://" + Domain,
AuthenticationType = AuthenticationTypes.Secure
};
return de;
}
Hello i try to write an application for a club that makes it easier for older member to use outlook and to send emails. Just a friendly way so elderly People can easy write and see the stuff on screen. But i am a novice programmer and never used the EWS managed API before. What i want is to Synchronice the Global Address List to my programm so i can assign them to an object and do more stuff. But i dont have any clues anymore.
What i tried:
For my own local Contact List (works)
private void AsignValuetoClass(object sender, RoutedEventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
//How many Contacts are in the folder
ContactsFolder contactsfolder = ContactsFolder.Bind(es, WellKnownFolderName.Contacts);
//To get a specific number of contacts
int numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
//object of the Itemview
ItemView view = new ItemView(numItems);
//return the stuff
FindItemsResults<Item> contactIds = es.FindItems(WellKnownFolderName.Contacts, view);
//loop throug the item
foreach (Item item in contactIds)
{
if (item is Contact)
{
//assign of the contact items
Contact contact = item as Contact;
//new list
List<Contact> testlist = new List<Contact>();
//Add the contacts
testlist.Add(contact);
//loop through contact list
foreach (Contact Liste in testlist)
{
//new object on every run
TestKlasse test = new TestKlasse();
//assign
test.id = Convert.ToString(contact.Id);
test.Vorname = contact.GivenName;
test.Nachname = contact.Surname;
}
Console.WriteLine("Some stupid Text");
}
}
}
To get the contacts from the GAL (dont work).
private void SearchContacts(object sender, EventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
NameResolutionCollection nameResolutions = es.ResolveName(
"Contacts",
ResolveNameSearchLocation.DirectoryThenContacts,
true);
foreach (NameResolution nameResolution in nameResolutions)
{
ExpandGroupResults groupResults = es.ExpandGroup(nameResolution.Mailbox.Address);
foreach (EmailAddress member in groupResults.Members)
{
Console.WriteLine(member.Name + " <" + member.Address + ">");
}
}
}
I tried also the resolvename() stuff but its only for one contact or matching contacts. I need every Contact. Here is the code:
private void SearchContacts(object sender, EventArgs e)
{
//For the connection
es.UseDefaultCredentials = true;
es.AutodiscoverUrl("max.mustermann#muster.at", RedirectionUrlValidationCallback);
// Identify the mailbox folders to search for potential name resolution matches.
List<FolderId> folders = new List<FolderId>() { new FolderId(WellKnownFolderName.Contacts) };
// Search for all contact entries in the default mailbox contacts folder and in Active Directory Domain Services (AD DS). This results in a call to EWS.
NameResolutionCollection coll = es.ResolveName("Anderl", folders, ResolveNameSearchLocation.ContactsThenDirectory, false);
foreach (NameResolution nameRes in coll)
{
Console.WriteLine("Contact name: " + nameRes.Mailbox.Name);
Console.WriteLine("Contact e-mail address: " + nameRes.Mailbox.Address);
Console.WriteLine("Mailbox type: " + nameRes.Mailbox.MailboxType);
}
}
Any help would be great so thx for your time. And sorry for my bad english.
This might come a bit late but one way to overcome the 100 user limit would be to simply append each character of the alphabet to "SMTP:" within a loop like this:
private _exchangeSvc = new ExchangeService();
const string SMTP_PREFIX = "SMTP:";
const string ABC = "abcdefghijklmnopqrstuvwxyz";
public List<NameResolution> GetGAL()
{
var gal = new List<NameResolution>();
foreach (char c in ABC)
{
string ambiguousName = SMTP_PREFIX + c;
var nameResCollection = _exchangeSvc.ResolveName(
ambiguousName,
ResolveNameSearchLocation.DirectoryOnly,
false);
gal.AddRange(nameResCollection);
}
//Uncomment the line below if you find duplicates.
// gal = gal.Distict().ToList()
return gal;
}
This worked for me when I needed the GAL via EWS, I only had to retrieve ~400 users though.
I'm trying to get the username of the current user in a web app that's running inside MS Dynamics 2011.
If I used Environment.UserName it returns the username of the AppPool the app is running under. How do I determine the actual user who is logged in to Dynamics?
Assuming that this is a website that is using windows authentication, this is how you can lookup the username of the request:
var name = Request.RequestContext.HttpContext.User.Identity.Name;
You can then use that name to lookup the SystemUserId of the user and do impersonation if need be.
Guid userGuid;
if(Request.LogonUserIdentity.IsAuthenticated == true)
{
WhoAmIRequest userRequest = new Microsoft.Crm.SdkTypeProxy.WhoAmIRequest();
WhoAmIResponse user = (Microsoft.Crm.SdkTypeProxy.WhoAmIResponse)objCrmService.Execute(userRequest);
userGuid = user.UserId;
}
else //ifd
{
userGuid = new Guid(Context.User.Identity.Name);
}
//Populating a dropdown with all users and selecting the current user
SelectUser(userGuid);
private void SelectUser(Guid userId)
{
BusinessEntityCollection users = LoadUsers();//Load all users
for (int i = 0; i < users.BusinessEntities.Count; i++)
{
DynamicEntity entity = (DynamicEntity)users.BusinessEntities[i];
if (entity.Properties.Contains(“systemuserid”) && ((Key)entity.Properties["systemuserid"]).Value == userId)
{
DDLUsers.Items.Add(new ListItem(entity.Properties["fullname"].ToString(), ((Key)entity.Properties["systemuserid"]).Value.ToString()));
DDLUsers.Items[i].Selected = true;
}
else
{
DDLUsers.Items.Add(new ListItem(entity.Properties["fullname"].ToString(), ((Key)entity.Properties["systemuserid"]).Value.ToString()));
}
}
}
I am developing a WPF-C# application and fetching MS Outlook 2010 contact items using Redemption. It is working fine if my Outlook has only one SMTP account. But if I configure another account which is exchange server account then I don't get any contact item from the same code. Following is my code:
Interop.Redemption.RDOItems folderItems = null;
Interop.Redemption.RDOFolder folderContacts = null;
Interop.Redemption.RDOFolder folderSuggestedContacts = null;
List<GMContactItem> allOutlookContacts = null;
object itemObj = null;
List<Interop.Redemption.RDOContactItem> contactItemsList = null;
try
{
folderContacts = (RDOFolder)RDOSessionItem.GetDefaultFolder(Interop.Redemption.rdoDefaultFolders.olFolderContacts);
contactItemsList = new List<RDOContactItem>();
folderItems = folderContacts.Items;
for (int i = 1; folderItems.Count >= i; i++)
{
itemObj = folderItems[i];
if (itemObj is Interop.Redemption.RDOContactItem)
contactItemsList.Add(itemObj as RDOContactItem);
else
Marshal.ReleaseComObject(itemObj);
}
Marshal.ReleaseComObject(folderItems);
folderItems = null;
// getting items from the Suggested Contacts folder in Outlook
folderSuggestedContacts = RDOSessionItem.GetDefaultFolder(
rdoDefaultFolders.olFolderSuggestedContacts);
if (folderSuggestedContacts != null)
{
folderItems = folderSuggestedContacts.Items;
for (int i = 1; folderItems.Count >= i; i++)
{
itemObj = folderItems[i];
if (itemObj is Interop.Redemption.RDOContactItem)
contactItemsList.Add(itemObj as Interop.Redemption.RDOContactItem);
else
Marshal.ReleaseComObject(itemObj);
}
}
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
When I delete my exchange server account then it work fine and if I add exchange server account in Outlook then this code has no exception but don't give any contact item. Can anybody suggest me that what could be the issue here. Thanks in advance.
-Surya
Are you looking at the GAL entries? These address entries exist in GAL (AD based), not in the Contacts folder of the Exchange mailbox.
If you need to open the Contacts folder of the (non-default) PST store, call RDOStore.GetDefaultFolder(olFolderContacts) instead of RDOSession.GetDefaultFolder (which returns a folder from the default store).
The secondary PST store can be opened using the RDOSession.Stores collection.
We have a public calendar for our company set up in an Exchange 2007 Public Folder. I am able to retrieve my personal calendar appointments for the current day using the code below. I have searched high and low online and I cannot find one example of someone retrieving calendar information from a Public Folder calendar.
It seems like it should be doable, but I cannot for the life of me get it working. How can I modify the code below to access the calendar? I am not interested in creating any appointments through asp.net, just retrieving a simple list. I am open to any other suggestions as well. Thanks.
ADDED BOUNTY
- I can't be the only person that ever needed to do this. Let's get this problem solved for future generations.
UPDATED AGAIN DUE TO IGNORANCE
- I failed to mention that the project I am working on is .NET 2.0 (very important don't you think?).
* ADDED MY CODE SOLUTION BELOW *
- I have replaced my original code example with the code that ended up working. Many thanks to Oleg for providing the code to find the public folder, which was the hardest part.. I have modified the code using the example from here http://msexchangeteam.com/archive/2009/04/21/451126.aspx to use the simpler FindAppointments method.
This simple example returns an html string with the appointments, but you can use it as a base to customize as needed. You can see our back and forth under his answer below.
using System;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace ExchangePublicFolders
{
public class Program
{
public static FolderId FindPublicFolder(ExchangeService myService, FolderId baseFolderId,
string folderName)
{
FolderView folderView = new FolderView(10, 0);
folderView.OffsetBasePoint = OffsetBasePoint.Beginning;
folderView.PropertySet = new PropertySet(FolderSchema.DisplayName, FolderSchema.Id);
FindFoldersResults folderResults;
do
{
folderResults = myService.FindFolders(baseFolderId, folderView);
foreach (Folder folder in folderResults)
if (String.Compare(folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0)
return folder.Id;
if (folderResults.NextPageOffset.HasValue)
folderView.Offset = folderResults.NextPageOffset.Value;
}
while (folderResults.MoreAvailable);
return null;
}
public static string MyTest()
{
ExchangeService myService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
myService.Credentials = new NetworkCredential("USERNAME", "PASSWORD", "DOMAIN");
myService.Url = new Uri("https://MAILSERVER/ews/exchange.asmx");
Folder myPublicFoldersRoot = Folder.Bind(myService, WellKnownFolderName.PublicFoldersRoot);
string myPublicFolderPath = #"PUBLIC_FOLDER_CALENDAR_NAME";
string[] folderPath = myPublicFolderPath.Split('\\');
FolderId fId = myPublicFoldersRoot.Id;
foreach (string subFolderName in folderPath)
{
fId = Program.FindPublicFolder(myService, fId, subFolderName);
if (fId == null)
{
return string.Format("ERROR: Can't find public folder {0}", myPublicFolderPath);
}
}
Folder folderFound = Folder.Bind(myService, fId);
if (String.Compare(folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0)
{
return string.Format("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath);
}
CalendarFolder AK_Calendar = CalendarFolder.Bind(myService, fId, BasePropertySet.FirstClassProperties);
FindItemsResults<Appointment> AK_appointments = AK_Calendar.FindAppointments(new CalendarView(DateTime.Now,DateTime.Now.AddDays(1)));
string rString = string.Empty;
foreach (Appointment AK_appoint in AK_appointments)
{
rString += string.Format("Subject: {0}<br />Date: {1}<br /><br />", AK_appoint.Subject, AK_appoint.Start);
}
return rString;
}
}
}
Like promised here is a code example. I used the Microsoft Exchange Web Services (EWS) Managed API 1.0 and recommend you to do the same. The most comments I included in the code
using System;
using Microsoft.Exchange.WebServices.Data;
using System.Net;
namespace ExchangePublicFolders {
class Program {
static FolderId FindPublicFolder (ExchangeService myService, FolderId baseFolderId,
string folderName) {
// We will search using paging. We will use page size 10
FolderView folderView = new FolderView (10,0);
folderView.OffsetBasePoint = OffsetBasePoint.Beginning;
// we will need only DisplayName and Id of every folder
// se we'll reduce the property set to the properties
folderView.PropertySet = new PropertySet (FolderSchema.DisplayName,
FolderSchema.Id);
FindFoldersResults folderResults;
do {
folderResults = myService.FindFolders (baseFolderId, folderView);
foreach (Folder folder in folderResults)
if (String.Compare (folder.DisplayName, folderName, StringComparison.OrdinalIgnoreCase) == 0)
return folder.Id;
if (folderResults.NextPageOffset.HasValue)
// go to the next page
folderView.Offset = folderResults.NextPageOffset.Value;
}
while (folderResults.MoreAvailable);
return null;
}
static void MyTest () {
// IMPORTANT: ExchangeService is NOT thread safe, so one should create an instance of
// ExchangeService whenever one needs it.
ExchangeService myService = new ExchangeService (ExchangeVersion.Exchange2007_SP1);
myService.Credentials = new NetworkCredential ("MyUser#corp.local", "myPassword00");
myService.Url = new Uri ("http://mailwebsvc-t.services.local/ews/exchange.asmx");
// next line is very practical during development phase or for debugging
myService.TraceEnabled = true;
Folder myPublicFoldersRoot = Folder.Bind (myService, WellKnownFolderName.PublicFoldersRoot);
string myPublicFolderPath = #"OK soft GmbH (DE)\Gruppenpostfächer\_Template - Gruppenpostfach\_Template - Kalender";
string[] folderPath = myPublicFolderPath.Split('\\');
FolderId fId = myPublicFoldersRoot.Id;
foreach (string subFolderName in folderPath) {
fId = FindPublicFolder (myService, fId, subFolderName);
if (fId == null) {
Console.WriteLine ("ERROR: Can't find public folder {0}", myPublicFolderPath);
return;
}
}
// verify that we found
Folder folderFound = Folder.Bind (myService, fId);
if (String.Compare (folderFound.FolderClass, "IPF.Appointment", StringComparison.Ordinal) != 0) {
Console.WriteLine ("ERROR: Public folder {0} is not a Calendar", myPublicFolderPath);
return;
}
CalendarFolder myPublicFolder = CalendarFolder.Bind (myService,
//WellKnownFolderName.Calendar,
fId,
PropertySet.FirstClassProperties);
if (myPublicFolder.TotalCount == 0) {
Console.WriteLine ("Warning: Public folder {0} has no appointment. We try to create one.", myPublicFolderPath);
Appointment app = new Appointment (myService);
app.Subject = "Writing a code example";
app.Start = new DateTime (2010, 9, 9);
app.End = new DateTime (2010, 9, 10);
app.RequiredAttendees.Add ("oleg.kiriljuk#ok-soft-gmbh.com");
app.Culture = "de-DE";
app.Save (myPublicFolder.Id, SendInvitationsMode.SendToNone);
}
// We will search using paging. We will use page size 10
ItemView viewCalendar = new ItemView (10);
// we can include all properties which we need in the view
// If we comment the next line then ALL properties will be
// read from the server. We can see there in the debug output
viewCalendar.PropertySet = new PropertySet (ItemSchema.Subject);
viewCalendar.Offset = 0;
viewCalendar.OffsetBasePoint = OffsetBasePoint.Beginning;
viewCalendar.OrderBy.Add (ContactSchema.DateTimeCreated, SortDirection.Descending);
FindItemsResults<Item> findResultsCalendar;
do {
findResultsCalendar = myPublicFolder.FindItems (viewCalendar);
foreach (Item item in findResultsCalendar) {
if (item is Appointment) {
Appointment appoint = item as Appointment;
Console.WriteLine ("Subject: \"{0}\"", appoint.Subject);
}
}
if (findResultsCalendar.NextPageOffset.HasValue)
// go to the next page
viewCalendar.Offset = findResultsCalendar.NextPageOffset.Value;
}
while (findResultsCalendar.MoreAvailable);
}
static void Main (string[] args) {
MyTest();
}
}
}
You should update the string myPublicFolderPath to the value with your public calender folder. I set myService.TraceEnabled = true which produce long output with debug information. You should of cause remove the line for production.
UPDATED: Some additional links you could find in Create new calendar system support in Exchange OWA. If you not yet seen the videos and you want to use Exchange Web Services I would recommend you to watch there. It could save your time in the future.
I did similar thing for Exchange 2003, but using WebDAV Search method (http://msdn.microsoft.com/en-us/library/aa143053%28v=EXCHG.65%29.aspx).
http://geekswithblogs.net/cskardon/archive/2008/12/01/hunting-those-elusive-public-folders-using-exchange-web-services-part.aspx may help.