Welcome to MSDN Blogs Sign in | Join | Help

How to resolve the EWS ErrorNoPublicFolderServerAvailable error.

If you are using Exchange Web Services (EWS) against Exchange 2007 SP1, you may run into an issue where you are getting the ErrorNoPublicFolderServerAvailable and the error message says it’s not a proper error code.   This error appears if you have set the ”Exchange2007_SP1”, your code is accessing public folder and there is no public folder on the Exchange server. 

 

Here is an example of what you might get back when using auto-generated proxies:

 

Exception Type - System.InvalidOperationException
Exception Message - Instance validation error: 'ErrorNoPublicFolderServerAvailable' is not a valid value for ResponseCodeType.

 

See, public folders not installed by default when Exchange 2007 is installed.  Service Pack 1 for Exchange 2007 added support for public access with EWS if you add the ”Exchange2007_SP1” header to your EWS call.

 

“messages.xsd “is used for schema validation. So, it needs to be correct in order for validation to work.  As of  rollup 4, these are the only "PublicFolder"  errors enumerated in messages.xsd:

 

    <xs:enumeration value="ErrorNoPublicFolderReplicaAvailable"/>

    <xs:enumeration value="ErrorOperationNotAllowedWithPublicFolderRoot" />

    <xs:enumeration value="ErrorPublicFolderRequestProcessingFailed"/>

    <xs:enumeration value="ErrorPublicFolderServerNotFound"/>

 

So…   where is ErrorNoPublicFolderServerAvailable?

 

Apparently the “ErrorNoPublicFolderServerAvailable” enumeration error code was left out of messages.xsd and that’s what’s causing the xml parser to say it’s not a valid error code.  The solution for making it a valid error code is to put that error code into the XSD as a viable error code.

 

The suggested thing to do is add the ErrorNoPublicFolderServerAvailable entry to messages.xsd (usually located under "C:\Program Files\Microsoft\Exchange Server\ClientAccess\exchweb\ews") and regenerating the proxies to see if it resolves the issue with the error. The only change to message.xsd file is to add an enumeration to the schema which covers this error.  

      <xs:enumeration value=ErrorNoPublicFolderServerAvailable"/>

Here is what to try for the work-around:

 

1.     Copy the services.wsdl, messages.xsd, and types.xsd files down from your CAS server onto your local machine where you're running the Visual Studio proxy generator.

 

2. Edit the file "messages.xsd." and add the enumeration value ErrorNoPublicFolderServerAvailable to the ResponseCodeType enumeration in that file. This means you'll add a line that looks like:

 

<xs:enumeration value="ErrorNoPublicFolderServerAvailable" />

 

3. Generate new proxy classes using the WSDL/XSD files on your local machine (instead of from the Exchange server)

 

Read the following for more information on the ”Exchange2007_SP1” header:

 

Updating Exchange Server 2007 Exchange Web Service Clients to SP1

http://blogs.msdn.com/exchangedev/archive/2007/09/06/updating-exchange-server-2007-exchange-web-service-clients-to-sp1.aspx

How do I force OWA to only the web page in Engish?

There is no supported way to do this.  OWA uses the IE language settings to decide which language to display. Remember that OWA is a web application and goes off of browser settings just like most every other web site out there.  During the intial log-in to OWA you can set the language to use in OWA.  You can also override the language setting once logged-into OWA.  However, there is no supported way of forcing Englishe or any other language to be a speicific language other than to change IE (or other browser) language settings.

Below is an unsupported work-around for this issue.   Such code would be not supported or advised to use with OWA – so its a “use at your own risk” deal.  While there is support for writing ISAPI extensions and filters, there is no developer support for getting such a filter to work with OWA traffic.  ISAPI filters/extensions are notorious for messing-up OWA.  If such a filter were to be used and you need to call in for support, you may be asked to remove such a filter for troubleshooting.

    How to hard code the language of OWA interface
    http://support.microsoft.com/default.aspx?scid=kb;en-us;q310599

    IIS 6.0: ISAPI Filters for Earlier Versions of IIS May Not Load
    http://support.microsoft.com/default.aspx?scid=kb;en-us;327611

 


 

Don't redistribute product DLLs unless you know its safe and legal to do so.

Redistribution of files in the “C:\Program Files\Microsoft\Exchange Server” folder and sub-folders is not advised/supported.  Yes, this does include the “C:\Program Files\Microsoft\Exchange Server\Public” folder also.  These files are installed when the Exchange 2007 (or later) tools are installed.  If you need these files with the minimal installation, then use the Exchange installer to install them – the box will need to be at least in an Exchange Admin role.  There is no installer/redistributable which can be included with an application install – you have to run the installer for Exchange.

 

Files in product folder are not to be redistributed unless there is documentations saying that they may be.  Please refer to the EULA (End User License Agreement) which accompanies the installer for Exchange and note the text on redistribution.  Many DLLs and other files are part of a system of interdependent files and registry entries; distribution of any set of files incorrectly may likely fail at some point unless those files were designed for such distribution.   

 

When developing using APIs which are tied to a product, it’s very important that the files of that product are not distributed unless you know that it’s safe and legal to do so –in many cases it’s not.  Including product DLLs (in this case Microsoft’s) or OS DLLs (i.e. from Windows) should always be avoided.  In some cases severe (unrecoverable/data damaging) problems can occur from including such components with an application install. 

 

Here are some (not all) Exchange 2007 DLLs developers commonly ask if they can redistribute:

 

Microsoft.Exchange.Data.Common.dll

Microsoft.Exchange.Data.Directory.dll

Microsoft.Exchange.Data.dll

 

Here are some related links:

 

Find End User License Terms for Microsoft Software Licensed by Microsoft or the Computer Manufacturer

http://www.microsoft.com/about/legal/useterms/default.aspx

 

Microsoft .NET Namespaces for Exchange

http://msdn.microsoft.com/en-us/library/aa580926.aspx

 

Handling results of calling Power Shell – Multivalve and string arrays.

http://blogs.msdn.com/webdav_101/archive/2008/02/08/handling-results-of-calling-powershell-multivalued-and-string-arrays.aspx

 

How the Runtime Locates Assemblies

http://msdn.microsoft.com/en-us/library/yx7xezcf(VS.85).aspx

 

Howto: Set multiple extended properties on a folder using raw XML for EWS with a POST

Hmmm, there are very few samples on setting multiple extended properties on folders using a POST to EWS... so, I thought I would blog one.

 

This sample can be used with:

     http://blogs.msdn.com/webdav_101/archive/2009/02/27/howto-post-xml-to-ews-using-exchangeservicebinding-credentials.aspx 

 

Note the following:

                The version is set.

                Each property being set is done under a separate SetFolderField node.

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">

  <soap:Header>

      <t:RequestServerVersion Version="Exchange2007_SP1" />

  </soap:Header>

  <soap:Body>

    <UpdateFolder xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"

                  xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">

      <FolderChanges>

        <t:FolderChange>

          <t:FolderId Id="AAMkAGYyN2JmMDM5LThiMGQtNDg2NC1iOTJiLTcwNTAzYzA4MTJmZgAuAAAAAADQwmwDLXTRQqgtmPQzUYndAQAD87SOmtYKQJJgvwQj7+EZAITQgdTRAAA="

                            ChangeKey="AQAAABYAAAAD87SOmtYKQJJgvwQj7+EZAITUPEsA"/>

          <t:Updates>

            <t:SetFolderField>

                <t:ExtendedFieldURI 

                                                DistinguishedPropertySetId="PublicStrings"

                        PropertyName="TestA"

                        PropertyType="String"/>

                       <t:Folder>

                 <t:ExtendedProperty>

                    <t:ExtendedFieldURI 

                                                DistinguishedPropertySetId="PublicStrings"

                        PropertyName="TestA"

                        PropertyType="String"/>

                    <t:Value>testa</t:Value>

                </t:ExtendedProperty>

                </t:Folder>

            </t:SetFolderField>

 

            <t:SetFolderField>

                <t:ExtendedFieldURI  

                                PropertySetId="A29B59B5-4B75-57B7-A24F-23D6CD6C556C"

                        PropertyName="FolderB"

                        PropertyType="String"/>

                       <t:Folder>

                 <t:ExtendedProperty>

                    <t:ExtendedFieldURI 

                                        PropertySetId="A29B59B5-4B75-57B7-A24F-23D6CD6C556C"

                        PropertyName="FolderB"

                        PropertyType="String"/>

                    <t:Value>TestColor</t:Value>

                </t:ExtendedProperty>

                </t:Folder>

            </t:SetFolderField>

 

            <t:SetFolderField>

                <t:ExtendedFieldURI 

                                PropertySetId="A29B59B5-4B75-57B7-A24F-23D6CD6C556C"

                        PropertyName="TestC"

                        PropertyType="Integer"/>

                       <t:Folder>

                 <t:ExtendedProperty>

                    <t:ExtendedFieldURI 

                                        PropertySetId="A29B59B5-4B75-57B7-A24F-23D6CD6C556C"

                        PropertyName="TestC"

                        PropertyType="Integer"/>

                    <t:Value>3</t:Value>

                </t:ExtendedProperty>

                </t:Folder>

            </t:SetFolderField>

 

          </t:Updates>

        </t:FolderChange>

      </FolderChanges>

    </UpdateFolder>

  </soap:Body>

</soap:Envelope>

 

Howto: Post XML to EWS using ExchangeServiceBinding credentials.

Here is a sample which shows how to use the connection of the Exchange Service Binding to do a POST to EWS using an XML string.   

 

 

// Sample calling code:

private void cmdExecute_Click(object sender, EventArgs e)

{

    string sRequest = string.Empty;

 

    bool bRet = false;

    

    string sResponse = string.Empty;

 

    bRet = EwsHelper.DoSoapRequest(

                sURL,

                oExchangeServiceBinding.Credentials,

                sRequestXml,

                ref sResponse

                );

 

    txtResponse.Text = sResponse;

}

 

// Sample of implementation:

 

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Xml;

using System.Xml.Serialization;

using System.Net;

using System.Windows.Forms;

using MyExplorerApp.MyWebServiceRef;

 

// -------------------------------------------------------------------------------------------------------------

// DoSoapRequest

//  sEwsUrl - this is the url to the exchange.asmx

//  oCredentials - this is the credentials object from the ExchangeServiceBinding.

//  EWSRequestString - What you are requesting

//  EWSResponseString - The response string.

// -------------------------------------------------------------------------------------------------------------

public static bool DoSoapRequest(string sEwsUrl, ICredentials oCredentials, string EWSRequestString, ref string EWSResponseString)

{

    bool bError = false;

    EWSResponseString = "";

    HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(sEwsUrl);

 

    webRequest.Method = "POST";

    webRequest.ContentType = "text/xml;utf-8";

    

    webRequest.Credentials = oCredentials;

 

    byte[] requestBytes = System.Text.Encoding.UTF8.GetBytes(EWSRequestString);

 

    webRequest.ContentLength = requestBytes.Length;

    using (Stream requestStream = webRequest.GetRequestStream())  // Fill Request.

    {

        requestStream.Write(requestBytes, 0, requestBytes.Length);

        requestStream.Flush();

        requestStream.Close();

    }

    string sError = string.Empty;

    HttpWebResponse webResponse = null;

    try

    {

        webResponse = webRequest.GetResponse() as HttpWebResponse; // Get Response

    }

    catch (WebException webException)

    {

        HttpWebResponse httpResponse = webException.Response as HttpWebResponse;

        using (Stream responseStream = httpResponse.GetResponseStream())

        {

            StreamReader reader = new StreamReader(responseStream);

            sError = reader.ReadToEnd();

            MessageBox.Show(sError, "Error");

            bError = true;

        }

    }

 

    XmlDocument doc = new XmlDocument();

    // Read Response Stream

    if (bError == false)

    {

        string sResponse = string.Empty;

        using (Stream responseStream = webResponse.GetResponseStream())

        {

            StreamReader reader = new StreamReader(responseStream, Encoding.ASCII);

            sResponse = reader.ReadToEnd();

        }

 

        EWSResponseString = sResponse;

    }

 

    webRequest.Credentials = null;

 

    return bError;

}

Example: How to use PS_INTERNET_HEADERS with cdo 1.21 for custom properties.

'This example uses PS_INTERNET_HEADERS for setting a custom property

const smbx="mymailbox"  ' TODO: Change
const ssrv="myserver"      ' TODO: Change
const mycdoInetPset = "8603020000000000C000000000000046"
const myXheader = "X-SPAM"  ' TODO: Change to your property


set oses=createobject("mapi.session")
oses.logon "", "", false, true, 0, true, ssrv & vblf & smbx
set omsg=oses.inbox.messages.getfirst
sfrom=omsg.fields.item(myXheader,myCdoInetPset).value
wscript.echo sfrom
omsg.fields.add myXheader, vbString, "I Hate Spam!", myCdoInetPset
omsg.update

set omsg=nothing
set oses=nothing

Sample: How to get the number of file attachments with EWS.

Since HasAttachments does not really give you the number of file attachments, we you will find that you need to work around it.  You can use code like that below to get the real count of file attachments on an item.

 

    // -----------------------------------------------------------------------------------------

    // GetFileAttachmentsCount

    //   Returns number of attachments on an item.

    // -----------------------------------------------------------------------------------------

    public static int GetFileAttachmentsCount(ExchangeServiceBinding binding, ItemIdType id)

    {

        int iAttachmentCount = 0;

 

        // Use GetItem on the Id to get the Attachments collection 

        GetItemType getItemRequest = new GetItemType();

        getItemRequest.ItemIds = new ItemIdType[] { id };

        getItemRequest.ItemShape = new ItemResponseShapeType();

 

 

        getItemRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

        PathToUnindexedFieldType hasAttachPath = new PathToUnindexedFieldType();

        hasAttachPath.FieldURI = UnindexedFieldURIType.itemHasAttachments;

        PathToUnindexedFieldType attachmentsPath = new PathToUnindexedFieldType();

        attachmentsPath.FieldURI = UnindexedFieldURIType.itemAttachments;

        // Add additional properties?

 

        getItemRequest.ItemShape.AdditionalProperties = new BasePathToElementType[]{

             hasAttachPath, attachmentsPath };

 

 

        GetItemResponseType getItemResponse = binding.GetItem(getItemRequest);

        ItemInfoResponseMessageType getItemResponseMessage = getItemResponse.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

 

        if (getItemResponseMessage.ResponseCode == ResponseCodeType.NoError)

        {

            ItemType item = getItemResponseMessage.Items.Items[0];

            // Don't rely on  HasAttachments - It does not mean what you thing it would.

            if ((item.Attachments != null) && (item.Attachments.Length > 0))

            {

 

                for (int attachmentIndex = 0; attachmentIndex < item.Attachments.Length; attachmentIndex++)

                {

                    FileAttachmentType almostAnAttachment = item.Attachments[attachmentIndex] as FileAttachmentType;

                    if (almostAnAttachment != null)

                    {

                        iAttachmentCount += 1;

                    }

                }

 

            }

 

        }

        return iAttachmentCount;

    }

Sample: Howto display a list of calendar items in ListView using EWS

Here is a helpful sample of using EWS to get a list of calendar items and displaying them in a ListView. 

 

You should be able to use this with he sample I published prior on creating a CalendarView:

 

Sample: Using Calendar Views with EWS.

http://blogs.msdn.com/webdav_101/archive/2009/01/05/sample-using-calendar-views-with-ews.aspx

 

The sample below calls GetFileAttachmentsCount, which I have blogge here:

 

Sample: How to get the number of file attachments with EWS.

http://blogs.msdn.com/webdav_101/archive/2009/01/10/sample-how-to-get-the-number-of-file-attachments-with-ews.aspx

 

OK, on to the sample:

 

    //-------------------------------------------------------------------------------------------

    // RequestAndDisplayCalendarFullView

    // Populates the ListView with a list of appointments defined in the calendar view.

    //-------------------------------------------------------------------------------------------

    public static void RequestAndDisplayCalendarFullView(

                ExchangeServiceBinding binding,

                CalendarViewType calendarView,

                ref ListView lvView)

    {

 

 

        FindItemType findItemRequest = new FindItemType();

        findItemRequest.ParentFolderIds = new DistinguishedFolderIdType[] { new DistinguishedFolderIdType() };

        ((DistinguishedFolderIdType)findItemRequest.ParentFolderIds[0]).Id =

            DistinguishedFolderIdNameType.calendar;

 

        findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

 

        ItemResponseShapeType itemShapeDefinition = new ItemResponseShapeType();

        itemShapeDefinition.BaseShape = DefaultShapeNamesType.AllProperties;

 

        findItemRequest.Item = calendarView;

        findItemRequest.ItemShape = itemShapeDefinition;

 

        // Do the EWS Call.

        FindItemResponseType findItemResponse = binding.FindItem(findItemRequest);

      

        if (findItemResponse.ResponseMessages.Items[0].ResponseClass !=

                ResponseClassType.Success)

        {

            // Indicate we have a problem

            throw new Exception(String.Format(

                "Unable to get calendar view\r\n{0}\r\n{1}",

                findItemResponse.ResponseMessages.Items[0].ResponseCode,

                findItemResponse.ResponseMessages.Items[0].MessageText));

        }

 

        FindItemResponseMessageType findItemResponseMessage =

            (FindItemResponseMessageType)findItemResponse.ResponseMessages.Items[0];

        ArrayOfRealItemsType findItemResponseItems =

            (ArrayOfRealItemsType)findItemResponseMessage.RootFolder.Item;

 

        ListViewItem lvItem = null;

        int iAttachmentCount = 0;

 

        lvView.Clear();

        lvView.View = View.Details;   // Set the view to show details.

        lvView.GridLines = true;      // Display grid lines.

        lvView.Columns.Add("Subject", 200, HorizontalAlignment.Left);

        lvView.Columns.Add("Recurring", 80, HorizontalAlignment.Left);

        lvView.Columns.Add("Start", 120, HorizontalAlignment.Left);

        lvView.Columns.Add("End", 120, HorizontalAlignment.Left);

        lvView.Columns.Add("Organizer", 80, HorizontalAlignment.Left);

        lvView.Columns.Add("#@", 40, HorizontalAlignment.Left);

        lvView.Columns.Add("Meeting", 80, HorizontalAlignment.Left);

 

        for (int x = 0;

            x < findItemResponseMessage.RootFolder.TotalItemsInView;

            x++)

        {

            CalendarItemType currentCalendarItem =

                (CalendarItemType)findItemResponseItems.Items[x];

 

            Debug.WriteLine(currentCalendarItem.Subject);

 

            lvItem = new ListViewItem(String.Format("{0}", currentCalendarItem.Subject, 0));

            lvItem.SubItems.Add(currentCalendarItem.IsRecurring.ToString());

            lvItem.SubItems.Add(currentCalendarItem.Start.ToLocalTime().ToString());

            lvItem.SubItems.Add(currentCalendarItem.End.ToLocalTime().ToString());

            lvItem.SubItems.Add(String.Format("{0}", currentCalendarItem.Organizer.Item.Name));

            iAttachmentCount = EwsAttachments.GetFileAttachmentsCount(binding, currentCalendarItem.ItemId);

            lvItem.SubItems.Add(String.Format("{0}", iAttachmentCount.ToString()));

            lvItem.SubItems.Add(String.Format("{0}", currentCalendarItem.IsMeeting.ToString()));

            lvItem.Tag = string.Format("{0}:{1}", currentCalendarItem.ItemId.Id, currentCalendarItem.ItemId.ChangeKey);

            lvView.Items.Add(lvItem);

 

            lvItem = null;

 

        }

    }

 

 

Ews; Exchange Web Services; list; appointments; appointment; calendaritem; DevMsgTeam; CalendarViewType; meeting;

Example: Populate a ListView with a list of attachments using EWS

I thought it would be fun to blog another sample of getting a list of attachments using EWS.  So, here is a handly method for populating a list of attachments.

 

    // -----------------------------------------------------------------------------------------

    // GetFileAttachmentsListLv

    //   Sets a listview to the attachments on an item.

    //   Returns number of attachments.

    // -----------------------------------------------------------------------------------------

    public static int GetFileAttachmentsListLv(ExchangeServiceBinding binding, ItemIdType id, ref ListView oListView)

    {

        int iAttachmentCount = 0;

        //List<RequestAttachmentIdType> attachmentIds = new List<RequestAttachmentIdType>();

 

        GetItemType getItemRequest = new GetItemType();

        getItemRequest.ItemIds = new ItemIdType[] { id };

        getItemRequest.ItemShape = new ItemResponseShapeType();

 

        getItemRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

        PathToUnindexedFieldType hasAttachPath = new PathToUnindexedFieldType();

        hasAttachPath.FieldURI = UnindexedFieldURIType.itemHasAttachments;

        PathToUnindexedFieldType attachmentsPath = new PathToUnindexedFieldType();

        attachmentsPath.FieldURI = UnindexedFieldURIType.itemAttachments;

        // Add  additional properties...?

 

        getItemRequest.ItemShape.AdditionalProperties = new BasePathToElementType[]{

             hasAttachPath, attachmentsPath };

 

        GetItemResponseType getItemResponse = binding.GetItem(getItemRequest);

        ItemInfoResponseMessageType getItemResponseMessage = getItemResponse.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

 

        oListView.Clear();

        oListView.View = View.Details;   // Set the view to show details.

        oListView.GridLines = true;      // Display grid lines.

        oListView.Columns.Add("Name", 90, HorizontalAlignment.Left);

        oListView.Columns.Add("Id", 120, HorizontalAlignment.Left);

        oListView.Columns.Add("RootItemId", 120, HorizontalAlignment.Left);

        oListView.Columns.Add("RootItemChangeKey", 120, HorizontalAlignment.Left);

        oListView.Columns.Add("ContentType", 80, HorizontalAlignment.Left);

        oListView.Columns.Add("ContentId", 80, HorizontalAlignment.Left);

        oListView.Columns.Add("ContentLocation", 80, HorizontalAlignment.Left);

 

        if (getItemResponseMessage.ResponseCode == ResponseCodeType.NoError)

        {

 

            ItemType item = getItemResponseMessage.Items.Items[0];

            // dont rely on item.HasAttachments - its mostly likely not set as you would think.

            if ((item.Attachments != null) && (item.Attachments.Length > 0))

            {

                for (int attachmentIndex = 0; attachmentIndex < item.Attachments.Length; attachmentIndex++)

                {

                    // For now, let's only consider file attachments instead of item attachments.

                    FileAttachmentType almostAnAttachment = item.Attachments[attachmentIndex] as FileAttachmentType;

                    if (almostAnAttachment != null)

                    {

                        // Note: Use GetAttachment to get the actual attachment.

 

                        RequestAttachmentIdType requestId = new RequestAttachmentIdType();

                        requestId.Id = almostAnAttachment.AttachmentId.Id;

 

                        ListViewItem lvItem = new ListViewItem(String.Format("{0}", almostAnAttachment.Name));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.AttachmentId.Id));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.AttachmentId.RootItemId));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.AttachmentId.RootItemChangeKey));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.ContentId));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.ContentLocation));

                        lvItem.SubItems.Add(String.Format("{0}", almostAnAttachment.ContentType));

                        oListView.Items.Add(lvItem);

 

                        lvItem = null;

 

                        iAttachmentCount++;

                    }

                }

 

            }

 

        }

 

        return iAttachmentCount;

    }

Sample: Using Calendar Views with EWS.

When working with Exchange Web Services (EWS) to do calendaring operations, you will likely run into the need to define calendar views.  A calendar view is a restriction/filer on the timespan of appointments and meetings you want to see in the calendar. To a beginner, how defining a calendar view properly can be a little bit confusing.  So, I put together some sample code I’ve used prior and am providing it here in case your looking for such samples.

 

 

Here is a sample of the calling code:

 

            CalendarViewType cvtView = GetCalendarViewForDay(2007,1, 6);

 

            txtDayView.Text = RequestAndDisplayCalendarView(_esb, cvtView);

 

Here is the implemented code:

 

        // -----------------------------------------------------------------

        // GetCalendarViewForToday

        // Returns a calendar view for today.

        // -----------------------------------------------------------------

        public static CalendarViewType GetCalendarViewForToday()

        {

            return GetCalendarViewForDay(

                    DateTime.Now.Year,

                    DateTime.Now.Month,

                    DateTime.Now.Day

                    );

        }

 

        // -----------------------------------------------------------------

        // GetCalendarViewForDay

        // Returns a calendar view for a given day.

        // -----------------------------------------------------------------

        public static CalendarViewType GetCalendarViewForDay(int iYear, int iMonth, int iDay)

        {

            DateTime dtToday12AM = new DateTime(iYear, iMonth, iDay, 0, 0, 0, DateTimeKind.Local);

            CalendarViewType calendarView = new CalendarViewType();

            calendarView.StartDate = dtToday12AM;

            calendarView.EndDate = calendarView.StartDate.AddDays(1);

            calendarView.MaxEntriesReturned = 99;

            calendarView.MaxEntriesReturnedSpecified = true;

            return calendarView;

        }

 

        // -----------------------------------------------------------------

        // GetCalendarViewForWeek

        // Returns a calendar view for the week of a given date.

        // -----------------------------------------------------------------

        public static CalendarViewType GetCalendarViewForWeek(int iYear, int iMonth, int iDay)

        {

            // create a date time instance which represents the day at 12:00:00am

            DateTime workDateTime = new DateTime(iYear, iMonth, iDay, 0, 0, 0, DateTimeKind.Local);

            DateTime FirstDOW = GetFirstDOW(workDateTime);

            DateTime LastDOW = GetLastDOW(workDateTime);

 

            CalendarViewType calendarView = new CalendarViewType();

            calendarView.StartDate = FirstDOW;

            calendarView.EndDate = LastDOW; 

            calendarView.MaxEntriesReturned = 99;

            // Don’t forget to set the specified flag

            calendarView.MaxEntriesReturnedSpecified = true;

            return calendarView;

        }

 

        // -----------------------------------------------------------------------

        // GetFirstDOW

        // Returns a the first day of the week for a given date.

        // In this routine, Sunday is considered to be the first day of the

        // However, the day considered to be the first day of the week may vary depending

        // upon culture. Cultural specific coding is not covered in this sample.

        // -----------------------------------------------------------------------

        public static DateTime GetFirstDOW(DateTime dtDate)

        {

            DateTime FirstDayofWeek = dtDate;

 

            //CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek

            switch (dtDate.DayOfWeek)

            {

                case DayOfWeek.Sunday:

                    FirstDayofWeek = dtDate;

                    break;

                case DayOfWeek.Monday:

                    FirstDayofWeek = dtDate.AddDays(-1);

                    break;

                case DayOfWeek.Tuesday:

                    FirstDayofWeek = dtDate.AddDays(-2);

                    break;

                case DayOfWeek.Wednesday:

                    FirstDayofWeek = dtDate.AddDays(-3);

                    break;

                case DayOfWeek.Thursday:

                    FirstDayofWeek = dtDate.AddDays(-4);

                    break;

                case DayOfWeek.Friday:

                    FirstDayofWeek = dtDate.AddDays(-5);

                    break;

                case DayOfWeek.Saturday:

                    FirstDayofWeek = dtDate.AddDays(-6);

                    break;

            }

            return FirstDayofWeek;

        }

 

        // -----------------------------------------------------------------------

        // GetLastDOW

        // Returns a the last day of the week for a given date.

        // In this routine, Sunday is considered to be the last day of the

        // However, the day considered to be the last day of the week may vary depending

        // upon culture. Cultural specific coding is not covered in this sample.

        // -----------------------------------------------------------------------

        public static DateTime GetLastDOW(DateTime dtDate)

        {

            DateTime LastDayofWeek = dtDate;

 

            //CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek

            switch (dtDate.DayOfWeek)

            {

                case DayOfWeek.Sunday:

                    LastDayofWeek = dtDate.AddDays(6);

                    break;

                case DayOfWeek.Monday:

                    LastDayofWeek = dtDate.AddDays(5);

                    break;

                case DayOfWeek.Tuesday:

                    LastDayofWeek = dtDate.AddDays(4);

                    break;

                case DayOfWeek.Wednesday:

                    LastDayofWeek = dtDate.AddDays(3);

                    break;

                case DayOfWeek.Thursday:

                    LastDayofWeek = dtDate.AddDays(2);

                    break;

                case DayOfWeek.Friday:

                    LastDayofWeek = dtDate.AddDays(1);

                    break;

                case DayOfWeek.Saturday:

                    LastDayofWeek = dtDate;

                    break;

            }

            return LastDayofWeek;

        }

 

        // -----------------------------------------------------------------------

        // GetCalendarViewForMonth

        // Returns a calendar view for a given year/month

        // -----------------------------------------------------------------------

        public static CalendarViewType GetCalendarViewForMonth(int iYear, int iMonth)

        {

            DateTime dtLastDayOfMonth = new DateTime(

                    iYear,

                    iMonth,

                    DateTime.DaysInMonth(iYear, iMonth)

                    );

 

            DateTime dtStart = new DateTime(

                    iYear, iMonth, 1,

                    0, 0, 0,

                    DateTimeKind.Local

                    );

 

            CalendarViewType calendarView = new CalendarViewType();

            calendarView.StartDate = dtStart;

            calendarView.EndDate = dtLastDayOfMonth;

            calendarView.MaxEntriesReturned = 100;

            calendarView.MaxEntriesReturnedSpecified = true;

            return calendarView;

        }

 

       //----------------------------------------------------------------------

        // GetCalendarItems

        // Returns a list of calendar items as text based on a calendar view.

        //----------------------------------------------------------------------

        public static string GetCalendarItems(

                    ExchangeServiceBinding binding,

                    CalendarViewType calendarView)

        {

            

            string sLine = "";

            string sLines = "";

 

            FindItemType findItemRequest = new FindItemType();

 

            findItemRequest.ParentFolderIds = new DistinguishedFolderIdType[] { new DistinguishedFolderIdType() };

            ((DistinguishedFolderIdType)findItemRequest.ParentFolderIds[0]).Id =

                DistinguishedFolderIdNameType.calendar;

 

            findItemRequest.Traversal = ItemQueryTraversalType.Shallow;

        

            ItemResponseShapeType itemShapeDefinition = new ItemResponseShapeType();

            itemShapeDefinition.BaseShape = DefaultShapeNamesType.AllProperties;

 

            findItemRequest.Item = calendarView;

            findItemRequest.ItemShape = itemShapeDefinition;

           

            // Do the EWS Call...

            FindItemResponseType findItemResponse = binding.FindItem(findItemRequest);

           

            // Check for errors?

            if (findItemResponse.ResponseMessages.Items[0].ResponseClass !=

            ResponseClassType.Success)

            {

 

                throw new Exception(String.Format( "Error:\r\n{0}\r\n{1}",

                    findItemResponse.ResponseMessages.Items[0].ResponseCode,

                    findItemResponse.ResponseMessages.Items[0].MessageText));

            }

            

    

            FindItemResponseMessageType findItemResponseMessage =

                (FindItemResponseMessageType)findItemResponse.

                    ResponseMessages.Items[0];

            ArrayOfRealItemsType findItemResponseItems =

                (ArrayOfRealItemsType)findItemResponseMessage.RootFolder.Item;

 

            sLine = string.Format(

                "There are {0} appointments between \r\n\t{1} on {2} and\r\n" +

                "\t{3} on {4}\r\n------------------------------\r\n",

                findItemResponseMessage.RootFolder.TotalItemsInView,

                calendarView.StartDate.ToLongTimeString(),

                calendarView.StartDate.ToLongDateString(),

                calendarView.EndDate.ToLongTimeString(),

                calendarView.EndDate.ToLongDateString());

            Debug.WriteLine(sLine);

            sLines = sLine;

 

            for (int x = 0;

                x < findItemResponseMessage.RootFolder.TotalItemsInView;

                x++)

            {

 

                CalendarItemType currentCalendarItem =

                    (CalendarItemType)findItemResponseItems.Items[x];

 

                Debug.WriteLine(currentCalendarItem.Subject);

               

                // Exchange stores all calendaring data in UTC time. So, convert to local

                // time so the person looking at the dates dont have to do the time math.

                sLine = "    Starts at: "+

                    currentCalendarItem.Start.ToLocalTime().ToShortTimeString()  +

                    " on " + currentCalendarItem.Start.ToLocalTime().DayOfWeek +

                    "  (" + currentCalendarItem.Start.ToString() + ")";

                Debug.WriteLine(sLine);

                sLines += sLine + "\r\n";

                sLine = "    Ends at: " +

                    currentCalendarItem.End.ToLocalTime().ToShortTimeString() +

                    " on " + currentCalendarItem.End.ToLocalTime().DayOfWeek +

                    "  (" + currentCalendarItem.End.ToString() + ")";

                Debug.WriteLine(sLine);

                sLines += sLine + "\r\n";

 

                Debug.WriteLine("    RecurrenceId: " + currentCalendarItem.RecurrenceId);

                Debug.WriteLine("    Id: " + currentCalendarItem.ItemId.Id);

                Debug.WriteLine("    ChangeKey: " + currentCalendarItem.ItemId.ChangeKey);

                Debug.WriteLine("    Organizer Name: " + currentCalendarItem.Organizer.Item.Name);

                Debug.WriteLine("    IsRecurring: " + currentCalendarItem.IsRecurring.ToString());

                Debug.WriteLine("    IsMeeting: " + currentCalendarItem.IsMeeting.ToString());

                Debug.WriteLine("    OriginalStart: " + currentCalendarItem.OriginalStart.ToString());

                Debug.WriteLine("    HasAttachments: " + currentCalendarItem.HasAttachments.ToString());

                Debug.WriteLine("    Attachments: ");

 

                sLines += "    RecurrenceId: " + currentCalendarItem.RecurrenceId+ "\r\n";

                sLines += "    Id: " + currentCalendarItem.ItemId.Id+ "\r\n";

                sLines += "    ChangeKey: " + currentCalendarItem.ItemId.ChangeKey+ "\r\n";

                sLines += "    Organizer Name: " + currentCalendarItem.Organizer.Item.Name+ "\r\n";

                sLines += "    IsRecurring: " + currentCalendarItem.IsRecurring.ToString()+ "\r\n";

                sLines += "    IsMeeting: " + currentCalendarItem.IsMeeting.ToString()+ "\r\n";

                sLines += "    OriginalStart: " + currentCalendarItem.OriginalStart.ToString()+ "\r\n";

                sLines += "    HasAttachments: " + currentCalendarItem.HasAttachments.ToString()+ "\r\n";

                sLines += "    Attachments: "+ "\r\n";

 

                // Note: You should not rely on the HasAttachments. 

                //  Please refer to: 

               //         Example: Returning a list of attachments using EWS

               //         http://blogs.msdn.com/webdav_101/archive/2009/01/05/example-returing-a-list-of-attachments-using-ews.aspx

 

                Debug.WriteLine("    xxxxxx  xxxxxx  xxxxxx  xxxxxx  xxxxxx");

                Debug.WriteLine("");

 

                sLines += "     \r\n  xxxxxx  xxxxxx  xxxxxx  xxxxxx  xxxxxx" + "\r\n";

                sLines += "" + "\r\n";

            }

 

            return sLines;

        }

Example: Returning a list of attachments using EWS

Here is a sample on getting and returning a list of attachments on an item using Exchange Web Services (EWS).

        //

        //-----------------------------------------------------------------------------------------

        // GetAttachmentsList.

        // Gets a list of file attachemnts on an item and puts them into <FileAttachmentType>.

        // Returns the number of attchments found.

        //

        // Here is how  you might call this code:

        //    List<FileAttachmentType> attachmentIds = null;

        //    string sLines = string.Empty;

        //    int iAttachments = 0;

        //    iAttachments = GetAttachmentsList(binding, currentCalendarItem.ItemId, ref attachmentIds);

        //    Debug.WriteLine(string.Format("{0} Attachments", iAttachments));

        //    foreach (FileAttachmentType oFileAttachmentType in attachmentIds)

        //    {

        //        sLines += "        Id:                " + oFileAttachmentType.AttachmentId.Id + "\r\n";

        //        sLines += "        RootItemId:        " + oFileAttachmentType.AttachmentId.RootItemId + "\r\n";

        //        sLines += "        RootItemChangeKey: " + oFileAttachmentType.AttachmentId.RootItemChangeKey + "\r\n";

        //        sLines += "        ContentId:         " + oFileAttachmentType.ContentId + "\r\n";

        //        sLines += "        ContentLocation:   " + oFileAttachmentType.ContentLocation + "\r\n";

        //        sLines += "        ContentType:       " + oFileAttachmentType.ContentType + "\r\n";

        //        sLines += "        Name:              " + oFileAttachmentType.Name + "\r\n";

        //        Debug.WriteLine(sLines);

        //    }

        //-----------------------------------------------------------------------------------------

        public static int GetAttachmentsList

            (

                ExchangeServiceBinding binding,

                ItemIdType id,

                ref List<FileAttachmentType> attachmentIds

            )

        {

 

            int iAttachmentCount = 0;

            attachmentIds = new List<FileAttachmentType>();

 

            GetItemType getItemRequest = new GetItemType();

            getItemRequest.ItemIds = new ItemIdType[] { id };

            getItemRequest.ItemShape = new ItemResponseShapeType();

 

            getItemRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

            PathToUnindexedFieldType hasAttachPath = new PathToUnindexedFieldType();

            hasAttachPath.FieldURI = UnindexedFieldURIType.itemHasAttachments;

            PathToUnindexedFieldType attachmentsPath = new PathToUnindexedFieldType();

            attachmentsPath.FieldURI = UnindexedFieldURIType.itemAttachments;

 

            // Add  additional properties...? 

 

            //

            getItemRequest.ItemShape.AdditionalProperties = new BasePathToElementType[]{

                 hasAttachPath, attachmentsPath };

 

            GetItemResponseType getItemResponse = binding.GetItem(getItemRequest);

            ItemInfoResponseMessageType getItemResponseMessage = getItemResponse.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

 

            if (getItemResponseMessage.ResponseCode == ResponseCodeType.NoError)

            {

 

                ItemType item = getItemResponseMessage.Items.Items[0];

                // Never rely on item.HasAttachments - its mostly likely not set as you would think.

                if ((item.Attachments != null) && (item.Attachments.Length > 0))

                    {

 

                    for (int attachmentIndex = 0; attachmentIndex < item.Attachments.Length; attachmentIndex++)

                    {

                        // For now, let's only consider file attachments instead of item attachments.

                        //

                        FileAttachmentType oFoundAttachment = item.Attachments[attachmentIndex] as FileAttachmentType;

                        if (oFoundAttachment != null)

                        {

                            attachmentIds.Add(oFoundAttachment);

                            //Debug.WriteLine(" Id: " + oFoundAttachment.AttachmentId.Id);

                            iAttachmentCount++;

                        }

                    }

                }

            }

 

            return iAttachmentCount;

        }

An Adventure: Building an ASP.NET application to call 64bit Powershell.

I keep seeing quesions on calling Exchange PowerShell from ASP.NET pop-up. Not all the banter I've seen on the web and elsewhere seems to be correct, I decided to look into this.  I see that some people end-up setting up speical accounts or putting the code into COM+ because they give up trying to make the calls work directly from ASP.NET.  So as a test, I'm trying to call "Enable-Mailbox" from C# code in an ASP.NET application.

 

There are a few things you should note about calling PowerShell.

1)      64bit code is not supported calling 32bit code. 

2)      32bit code is not supported calling 64bit code.

3)     Only the 64bit version of Exchange is supported for production.

4)     You can put the 32 bit version Exchange admin tools of 2007 on a box and use PowerShell automation to work with Exchange 64bit.

5)     The proper refernce to System.Management.Automation.dll is: C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll
The location of this dll is improperly documented as being in other folders - so watch out.
So, no its not under C:\WINDOWS\system32\windowspowershell\v1.0 or C:\WINDOWS\SysWOW64\windowspowershell\v1.0
You will be using the same reference for building 32bit or 64bit automation apps.

6)     On a 64bit Exchagne server, you will be using the 64bit version of Powershell - this means that your application will need to be 64bit if the code runs on that box.

7)     If you put CDOEXM and PowerShell automation calls into the same program, then your likely to run into issues - so dont do it.

8)     If you want to do impersonation, you should be on the latest and greatest updates for Exchange.  If your calling PowerShell from box like Vista, be sure that both the Exchange server and the Vista box (used to call PowerShell) have been patched. 

 

OK, first hurdle here...     

When buuilding under VS 2008, I ran into issues with 64bit code under ASP.NET.  While calling "config.AddPSSnapIn"

worked from my WinForm application, I got an error from the WebForm.

 

"No Windows PowerShell Snap-ins are available for version 1."

 

So, whats going on here?  I did some checking and it seems to be related to calling 64bit

PowerShell from 32bit code. So, I set the code as targeted as 64bit in the solution properties.

 

Next, I got:

 

Warning      1          C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\ExchangePowerShellAdmin\ExchangePowerShellAdmin\Default.aspx: ASP.NET runtime error: Attempted to load a 64-bit assembly on a 32-bit platform. Use ReflectionOnlyLoad() instead if trying to load for reflection purposes.      C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\ExchangePowerShellAdmin\ExchangePowerShellAdmin\Default.aspx  1          1      ExchangePowerShellAdmin

 

WOW… looks interesting…

 

OK, specifying the platform as 64bit alone for the solution does not make it 64bit....?

So, I did more checking and found that that the Configuration Manager was not showing in the menu.  What gives?

Where has the Configuration manager setings gone???  I did some checking and found how to make it visible.

 

  #1 Make the Configuration Manager visiable in the menu:

            Go to: Tool -> Options -> Projects and Solutions -> General

            Check "Show advanced build configurations".  Yep, its not checked by default.

    Note: Now, you can get to the Configuration Manager under Build -> Configuration Manager.

   

  #2 Build the configuration for 64bit.

    Go to: Build -> Configuration Manager

    Create a 64bit build...

   

  #3 Go back to the solution and set as 64bit.

   

Now I can build this as 64bit, eh?  Ummm... I'm getting another error... says I'm referencing the the wrong assemblies for the processor.

Looks like Visual Studion does not automatically change these over.

 

Example:   Warning 1          Assembly generation -- Referenced assembly 'System.Web.dll' targets a different processor      WebApplication1

 

These warnings are ignorable, however I don't like unresolved warnings of any

kind - so, I removed the references to System.Data.DLL, System.Web.dll and

System.Enterprise Services. Next, I added-in new references to the 64bit

version of these assemblies.

 

c:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Data.dll

            c:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Web.dll

            c:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.EnterpriseServices.dll

           

Next in the solutions Build -> Advanced Build Settings windows I unchecked

“Do not reference mscorlib.dll” . This prevents VS from automatically adding

a reference to the 32bit version of mscorlib.dll. The problem here is that doing so caused

an error to be thrown during compilation:

 

    Error 1          Predefined type 'System.Object' is not defined or imported        ExchangePowerShellAdmin

 

Ahhhh... so, I'll uncheck “Do not reference mscorlib.dll” and live with the warnining for now.

 

So, is it working?  

   ... NO...

  

   I'm still getting  "No Windows PowerShell Snap-ins are available for version 1." .

 

I went into the solution settings for Web->Server and changed the appliation to use IIS

instead of Visual Studio.  Be sure to specify the virtual directory folder when doing

this - you likely dont want your app written to the sites root.  I compiles and ran - ok,

says I need to turn Windows auth to debug. I turned on Windows Auth from IIS and it ran.

 

Soooo....  changing the solution to run the Winform from IIS instead of from Visual Studio's

Development Server seems to help get rid of the "No Windows PowerShell Snap-ins are available

for version 1." message. - at least it seems to be a factor here.

 

Hold on - Windows auth is on and I'm signed-in as Admin... so I need to be sure that this

thing works when impersonation is used. Ok, it works out of the domain - I'm using Anonymous. 

Here is a clip from my web.config:

 

<authentication mode="None"/>

<authorization>

    <allow users="*" />

</authorization>

 

 So, it seems to all work now.  I'm using the code from a prior post I did on PowerShell Impersonation if your curious:

 

http://blogs.msdn.com/webdav_101/archive/2008/09/25/howto-calling-exchange-powershell-from-an-impersonated-thead.aspx

   

The one change I did though was to move the call to BeginImpersonation above config.AddPSSSnapIn. However, I would think it would be best to have AddPSSSnapIn called first.

 

In my test, I did not setup any special account.  The calls however are being done with the thread being impersonated as noted in the article link above.

 

I'll try to write-up some concise instructions on how to build an ASP.NET application for 64bit in the future.

 

 

WebDAV FBA Authentication Sample Explained.

 Here is some basic information on how FBA authentication is done with WebDAV.  To provide some insight into how this works, you should look at the sample code of KB891748 and review it with the explanation below.  Note that if you are going against Exchange 2007, you should reconsider using FBA authentication since FBA authentication is really for OWA and the settings for OWA and WebDAV are separate under 2007 – please refer to the links below for further information.

 

891748 How to programmatically access your Exchange Server 2003 Inbox using

http://support.microsoft.com/?id=891748

 

If FBA is enabled in the Exchange System Manager (ESM), then WebDAV will need to authenticate using FBA authentication.  In order to use FBA, SSL should be to configured and enabled in addition to turning on FBA in ESM.  Please note that the machine running the WebDAV code with an SSL URL will need to have the certificate installed on it.

 

Enabling FBA is controlled by checking the “Enable Forms Based Authentication” found under the properties of the HTTP protocol for the Exchange server in the Exchange System Manager.

 

You may be prompted to setup SSL if it’s not already.  If you don’t want to setup SSL, there is a work-around.  Even though it’s not advised, you can use FBA without SSL.  This is not advised because credentials will be passed in clear text – which could be sniffed.  To configure FBA to work without SSL for your development environment follow these steps:

1.     Open the registry editor (run regedit.exe)

2.     If it doesn’t exist already add an OWA key under:
HKLM\System\CurrentControlSet\Services\MSExchangeWeb

3.     Under the OWA key add a DWord value named “AllowRetailHTTPAuth”

4.     Set the value of this DWord to “1”

 

This is generally how it works:

1    An HTTP POST is done to /exchweb/bin/auth/owaauth.dll with an authentication string.

 

2)   The authentication string looks like this:

 

Dim strServerName as string = “Myserver”

Dim strDomain as string = “myserverdomain.something.com”

Dim strUserName as string = “myuser”

Dim strPassword as string = “mypassword”

 

Dim strPostFields As String = "destination=https%3A%2F%2F" & strServerName & "%2Fexchange%2F" + strUserName + "%2F&username=" + strDomain + "%5C" + strUserName + "&password=" + strPassword + "&SubmitCreds=Log+On&forcedownlevel=0&trusted=0"

 

3)   WebReq.KeepAlive and AllowAutoRedirect should be set to True on the request.

 

4)   Note: If you are doing an asynchronous call, you need to wait for the response – or the code will fail.  For .NET you could setup a callback.

 

5)   In the response from the POST, you will get back cookie strings in the headers.  These strings need to be extracted and placed into one string.  This will hold your credentials for future WebDAV calls.  These credentials will be good for a period of time (most often 20 minutes depending upon settings).

 

6)   Now that you have the credentials, a header of “Cookie" with the data consisting of the combined cookie strings in each WebDAV call you make.

 

WebDAVRequest.Headers.Add("Cookie", strReusableCookies)

 

7) If you get a response from the WebDAV call saying "The operation has timed-out.", then the credentials have expired. You will need to get new credentials (start with step 1) and do the WebDAV call again.

 

Further information:

 

WebDAV and OWA Authentication Settings

http://blogs.msdn.com/webdav_101/archive/2008/12/12/webdav-and-owa-authentication-settings.aspx

 

How WebDAV - Use Basic Authentication with WebDAV even when FBA is enabled.

http://blogs.msdn.com/webdav_101/archive/2008/02/01/how-webdav-use-basic-authentication-with-webdav-even-when-fba-is-enabled.aspx

 

 

WebDAV and OWA Authentication Settings

With any login issue, it’s important to know which authentication protocols are valid.  You  have to code to an authentication protocol which can be used.

 

The authentication settings for OWA and WebDAV are tied together under Exchange 2000 and 2003.  Because of this, developers run into issues with WebDAV not being able to authenticate if FBA is enabled for OWA.  A developer could work around the issue so they  don’t have to code for FBA authentication.  However, it’s common for developers to use custom FBA authentication code.

 

When trying to log-into OWA 2000 or 2003:

If it shows an asp login page, then FBA is enabled.

If you get a grey dialog box, then Basic is enabled.

If you go right into your email account, then windows auth is used.

 

Exchange 2007 is different than 2000/2003 because the settings for the Exchange virtual folder and OWA folder are separate – they don’t mess with each other.  Because of this you can set individual settings for WebDAV and OWA – so having FBA on for OWA will not affect WebDAV.   Please note that under 2007 you won’t be able to tell what settings there are for WebDAV by using the OWA login test mentioned above – you’ll have to check the IIS and ESM settings. 

 

One thing to note that for using WebDAV under 2007 is that there is no practical reason to use FBA authentication.  Why???   That’s because FBA authentication is really for authenticating against the OWA Web Page – and that’s not needed since the OWA and WebDAV settings are not separate.  You should consider using use Basic Authentication or Windows Authentication instead.   If your worrying about security, use SSL.  SSL will help prevent sniffing of passwords with Basic Authentication same as it does for FBA authentication.

 

Places to check for 2003:

 

In ESM:

If FBA is turned on, then they won’t be able to use Windows auth or Basic auth.  The FBA setting in ESM will override the IIS Settings.  ESM is the recommended place to change the settings on Exchange virtual folders – so you should set them here instead.  The settings between ESM and IIS are synced, however I’ve seen cases where they are not synchronized – so I’d suggest that you set them in ESM, then verify that they are correct in IIS.

 

In IIS: 

The Directory Security settings on the “exchange” virtual folder should be set as needed.  If Anonymous is turned on for the Exchange virtual folder, then Basic and Windows won’t be used.    

 

Note:   With some virtual folder (perhaps “exadmin”), you might have to set the settings in IIS because they will be grayed-out. 

 

Please refer to the following:

 

How WebDAV - Use Basic Authentication with WebDAV even when FBA is enabled.

http://blogs.msdn.com/webdav_101/archive/2008/02/01/how-webdav-use-basic-authentication-with-webdav-even-when-fba-is-enabled.aspx

 

WebDAV FBA Authentication Sample Explained.

http://blogs.msdn.com/webdav_101/archive/2008/12/12/webdav-fba-authentication-sample-explained.aspx

 

Howto: Accept meeting requests with VB6 and CDO 1.21

Here is a sample to accept all meeting requests using CDO 1.21.

' The code below will accept all meeting requests in the users inbox.
Private Sub cmdAcceptRecurringMeeting_Click()
   Dim objSession As mapi.Session
    Dim ObjMessage As mapi.Message
    Dim oMessages As mapi.Messages
    Dim oAppointment As mapi.AppointmentItem
    Dim oFolder As mapi.Folder
    Dim objOrig As AppointmentItem
    Dim objRecPatt As RecurrencePattern
    Dim oRecipients As mapi.Recipients
    Dim oRecipient As mapi.Recipient
    Dim oMeetingReq As mapi.MeetingItem
    Dim oMeetingRes As mapi.MeetingItem

    'Create the Session Object.
    Set objSession = New mapi.Session
   
    'Logon using the session object.
    'objSession.Logon "", "", False, True, 0, True, "myserver" & vbLf & "mymailbox"
    objSession.Logon
   
    Set oFolder = objSession.GetDefaultFolder(CdoDefaultFolderInbox)
    Set oMessages = oFolder.Messages
    
    Set oMeetingReq = oMessages.GetFirst
    Do While Not oMeetingReq Is Nothing
        Dim sType As String
        Dim lClass As Long
        sType = oMeetingReq.Type   '"IPM.Schedule.Meeting.Request"
        lClass = oMeetingReq.Class
 
        If (sType = "IPM.Schedule.Meeting.Request" And lClass = CdoMeetingItem) Then
            Set oMeetingRes = oMeetingReq.Respond(CdoResponseAccepted)
            oMeetingRes.Send True
            Set oMeetingRes = Nothing
        End If
    
        Set oMeetingReq = oMessages.GetNext
     Loop
    objSession.Logoff
 
End Sub

More Posts Next page »
 
Page view tracker