Welcome to MSDN Blogs Sign in | Join | Help

Jive into Messaging world

Everyday is a Challenge, I am loving it...

News

BUG: Outlook 2003: Custom Forms: You cannot use Custom Actions to Reply/Forward Appointment Items

I had been working on this issue lately where customer was using Outlook 2003 to create custom actions. It is not very commonly used thing so you might not know about it, at least I was not very much aware about it.

To do that, you have to open a form in design mode and go to Actions tab, hit the New action button down in the bottom left corner.

Give it the name of your choice and select “Appointment” type form from “Standard Forms” template. It will look something like this..

image

Publish this form and send it to your self.

Once sent, it will come up like this to your inbox, see the “CustomAction” button (this is the name that you provided)

image

Once you click this button, it should open a new Appointment form like when you do a forward or reply button, but instead of doing that it shows an error.

Error: "Could not complete the operation. One or more parameter values are not valid"

image

I found this problem to be related with build number Outlook 2003 11.8313.xxxx (SP3) and it does not reproduce with the standard install of Outlook 2003 SP3 (build 11.8169.8172).

So who caused it? Looks like that a latest security update has caused this issue.

Security Update for Microsoft Office Outlook 2003 (KB973705)

I have tried to uninstall this update and it started to work just fine, installed it back and it breaks again.

Since Outlook 2003 is out of commercial support lifecycle, you may or may not get an hotfix for this. If you have a business justification and this issue is causing trouble to you then please do not hesitate to contact me.

If we ever decide to fix it, then I will update this post and update you all.

PS.: The only possible workaround, though highly not recommended, is to uninstall the security update but be aware of the risks of doing so.

Happy Debugging!!!

BUG: Outlook: Word: A signature to death!

I have been working lately with this customer who was trying to create new signature files under %APPDATA%\Microsoft\Signatures folder which will be used by Outlook 2007 (SP2) but what we discovered is that whenever they try to use it, it used to crash Outlook.

This was the content of the HTML Signature file that we were using.

<HTML>
<BODY>
<IMG SRC="http://www.server.com/logo.jpg" />
</BODY>
</HTML>

Let’s save this HTML file to %APPDATA%\Microsoft\Signatures\CrashMe.htm

Now next thing you need to do is make sure that Outlook’s Mail Format is HTML

image

Next you need to make sure that “Typing replaces selected text” is unchecked under Tools->Options->Mail Format->Editor Options->Advanced

image

Once you done it all, now we load a new email item and insert our signature into the body and just try to save the message, and it will crash the Outlook.

Root Cause:

I am not very much sure but its not Outlook’s fault at all, Outlook is just a victim and its Word libraries at fault which are used to Edit the email message.

Workaround:

Since there is no solution at this moment, here are your workarounds.

1) Create the signature file using Outlook’s Signature Designer

2) Do not use HTML as default format for emails, either use RTF or Text

3) Do not uncheck the ‘Typing replaces selected text’ option, keep it selected

The word team is working on it and I shall update you all when I have some more information on this.

Happy Debugging.

Hey!!! Do not forget to “Include” me… Ok?

I am not talking about some Friday night dinner or the latest buff around the corner. I am talking about the “Include” tab on Outlook 2007’s Ribbon UI.

Recently I got this case where customer developed a custom email form but he was not able to use the “Include” tab to add attachments to the email, as you can see from the following screenshot.

image

All the buttons were grayed-out, but why? Customer had no clue, well that’s why he called Microsoft, isn’t it?

I tried to reproduce it locally, but first I opened up the custom form which customer was using and the initial discovery was that there was no message body included to it. That ring some bells to me, but I ignored that for the moment and tried to dig if there is any property that I can set to disable that Include tab but there were none. I also checked if there was any code behind, but there was none.

Now that I know what was present in form, and what was not, I decided to start from scratch and created a new form. And discovered the following.

The issue here is that the customer has deleted the standard “Message” field (which is used to write the email content) from the message, this field is also used to insert attachments, business cards, calendar & other stuff by Outlook.

Repro Steps

1) Open a new email inspector
2) Go to Developers Tab
3) Hit Design Mode
4) Delete the Message body
5) Run the Form and you will see the “Include” as grayed out.

Good now we know that was the culprit, but I do not need that message body on my form.. how do I fix it?

Workaround

1) We need to add the Message Body back to the form
2) Open the form in Design Mode again and drag & drop the “Message” back to the form 
3) Now you might not want that “Message Body” to be visible, but if you set the “Message Body” visible state
   to false then you will again not be able to add attachments as the body is not visible.
4) Another workaround, you need to keep the visible state as visible but make body’s height & width set to 0 to hide it from screen

Bingo!! That was it.. yeah now it works.

..but what a minute..why?

Overall, that's a general design decision they made a long time ago. That first page of the message form has a lot of dependencies on commands, etc. So once you do a "simple" thing like delete the body control, you run some big risks. It's up to the form developer to really scope all of that out, disable other commands if they need to, etc.

Happy Debugging!!!

3 years of same, yet different work and then a responsibility upgrade, a good one.

It’s been 3 very long and cherished years of my life as I complete my 3 years of career at Microsoft India GTSC, based out of Bangalore, India.

clip_image002A Bachelor in Computer Sciences was just a degree I acquired to certify my geek level. I was much more interested in practical knowledge than theoretical and decided to work a freelance along during my final years of graduation. After 4 years of working in different roles in IT industry,  as an independent consultant, system administrator , business analyst or software engineer, I got the opportunity to work with the Industry leader and decided to join Microsoft India GTSC & Developer Messaging Team in May 2006 as Support Engineer.

Joining Microsoft was the beginning of my career in the real sense of the word, working with great minds & mentors brought me up to this level. Exchange has always been my favorite, seeing it grow from 5.5 to E14 and being part of this growth brings me immense pleasure. I am very excited to take up the role of Support Escalation Engineer and hoping to continue my legacy of providing the best and exceeding the limits.

Happy Coding Debugging!!!

Using CDOSYS from .Net?! Be Careful with Attachments!

First off there is no justification why you should be using Cdosys directly, you should use System.Web.Mail if you are still on .Net 1.1 otherwise you should upgrade to System.Net.Mail.

Anyways, the problem I want to mention is when you use CDOSYS.dll directly from .Net 1.1 or 2.0 or even 3.5, the problem is with memory management.

Take this sample code..

Function SendMail()
        Dim iMsg As New CDO.Message
        With iMsg
            .To = "test@server.com"
            .From = "test@server.com"
            .Subject = "Hello, This is a test mail !"
            .HTMLBody = "<b>Hi</b>, <i>This is a test <u>HTML</u> mail !</i>"
            .AddAttachment("d:\attachment.txt")
        End With
        iMsg = Nothing
End Function

Looks short and sweet like there is nothing wrong with this, think again!

This code is holding the reference to File Handle and not going to release it even after you set iMsg = Nothing

The solution here is to release the COM Object (CDOSYS) properly by calling GC.Collect() followed by GC.WaitForPendingFinalizers() but outside of this code block.

Now consider this sample…

Function SafeSendMail()
        SendMail()
        Gc.Collect()
        GC.WaitForPendingFinalizers()
End Function

Function SendMail()
        Dim iMsg As New CDO.Message
        With iMsg
            .To = "test@server.com"
            .From = "test@server.com"
            .Subject = "Hello, This is a test mail !"
            .HTMLBody = "<b>Hi</b>, <i>This is a test <u>HTML</u> mail !</i>"
            .AddAttachment("d:\attachment.txt")
        End With
        iMsg = Nothing
End Function
This will make sure that the CDOSYS is collected as soon as you leave the SendMail block otherwise you won’t be able to access the file for writing/deleting it.

Happy Debugging!!!

Exchange Web Services 101 : Let’s get started!

Want to learn Exchange Web Service but not sure how and from where? Here are the few articles that I share very often with partners and customers who want to learn more about Exchange Web Services.

Undoubtedly there is so much information out there and that’s too in such a short span of time. You better start with Inside Exchange Web Services book from MSPRESS and then the rest of the articles can be utilized.

 

MSPRESS BOOK

  • Inside Microsoft Exchange Web Services

http://www.microsoft.com/learning/en/us/books/10724.aspx

Note: This book target Exchange 2007 RTM and does not talk about features introduced in Exchange 2007 Sp1 & later

  • Common EWS Operations

http://blogs.msdn.com/vikas/archive/2007/07/27/howto-getfolder-finditem-restriction-getitem.aspx

  • Working with attachments

http://blogs.msdn.com/vikas/archive/2007/10/16/howto-ews-add-attachments-to-existing-items-on-server.aspx

  • Links on Common Exchange Web Services (EWS) Questions

http://blogs.msdn.com/webdav_101/archive/2008/10/02/links-on-common-exchange-web-services-ews-questions.aspx

  • Generating list of calendar items using EWS

http://blogs.msdn.com/webdav_101/archive/2009/01/10/sample-howto-display-a-list-of-calendar-items-in-listview-using-ews.aspx

  • Understanding and Fixing Slow Exchange Web Services Code

Part 1

http://blogs.msdn.com/mstehle/archive/2008/07/17/outbox-understanding-and-fixing-slow-exchange-web-services-code-part-1.aspx

Part 2

http://blogs.msdn.com/mstehle/archive/2008/08/13/outbox-understanding-and-fixing-slow-exchange-web-services-code-part-2.aspx

Exchange Notifications

  • Exchange Web Services – Notification Subsystem

http://blogs.msdn.com/vikas/archive/2007/08/28/ews-exchange-2007-notification-subsystem.aspx

  • Transitioning to Exchange Web Services Notifications (from Store Events Sinks)

http://blogs.msdn.com/exchangedev/archive/2008/07/24/transitioning-to-exchange-web-services-notifications.aspx

Note: Notification Watermarks are valid for 30 days after which they expire

Exchange Managed API

Videos –

http://channel9.msdn.com/pdc2008/BB46/

http://msexchangeteam.com/archive/2009/03/24/450892.aspx

  • Introducing the EWS Managed API 1.0

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

  • EWS Managed API 1.0 Beta SDK April 2009

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

  • Exchange Server Developer Center

http://msdn.microsoft.com/en-us/exchange/default.aspx

 

Please do let me know if that information is helpful to you.

HOWTO: Automatically Login to OWA 2007 using HTML + JavaScript

First thing first, you should understand that this is NOT SUPPORTED & NOT RECOMMENDED solution by Microsoft.

This is just a proof of concept that OWA 2007 can be auto login, if you know the username & password of target account.

The approach is simple and took me little reverse engineering or OWA’s login page. Owa login page being HTML does a form submit and post the username/password along with few hidden variables and upon receiving those parameters owaauth.dll generate a cookie, assign it to the session and redirect you to your mailbox. How easy, you may say.. but how you can submit those parameters programmatically.

This is how its done…

<script>
function LoginToOWA (server,domain,username,password) {
  
  
  var url = "https://" + server + "/exchweb/bin/auth/owaauth.dll";
  var p = {destination:'https://' + server + '/exchange',flags:'0',forcedownlevel:'0',trusted:'0',isutf8:'1',username:domain + '\\' + username,password:password};
  
  
  var myForm = document.createElement("form");
  myForm.method="post" ;
  myForm.action = url ;

  for (var k in p) {
  
    var myInput = document.createElement("input") ;
    myInput.setAttribute("name", k) ;
    myInput.setAttribute("value", p[k]);
    myForm.appendChild(myInput) ;
  }
    
  
  document.body.appendChild(myForm) ;
  myForm.submit() ;
  document.body.removeChild(myForm) ;
}
</script>

<body onload="javascript:LoginToOWA('owa.exchange.com','domain','username','password');">
<h3>Please wait while redirecting to OWA...</h3>
</Body>
Happy Coding!!!
 
Share this post :
HOWTO: EWS: Get OOF State for Self or any user in your organization

First thing first, this is just for demonstration purpose and might *not* be a supported solution by Microsoft. The setting we are reading from are hidden messages and not documented anywhere. I had to reverse engineer it for demonstration purpose.

Objective: To get OOF State of any user in your organization.

Challenges: You might ask me why not use GetUserOofSettings to query user’s OOF status with the help of Exchange Impersonation? This is due to the limitation of EWS’s GetUserOofSettings/SetUserOofSettings methods as they don’t support Impersonation.

Workaround: Directly reading the hidden messages from Mailbox Root where this Flag & OOF message is stored. Since we are read-only we should be good to do so, that’s my assumption.

We need to first make a FindItem call to the mailbox root and search for a message with ItemClass = “IPM.Microsoft.OOF.UserOOFSettings”. Assuming that there will be only one message with that message class at any given time, we get its ItemId and make a GetItem call to read the message body. The message body is plain text XML with following structure

 

For OOF enabled…

<UserOofSettings>
<OofState >Enabled</OofState>
</UserOofSettings>

For OOF disabled…

<UserOofSettings>
<OofState >Disabled</OofState>
</UserOofSettings>

There is also a state called SCHEDULED, please refer to the below mentioned article to know more about it

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

This code sample can do the job for you.

using System;
using GetOOFState.MyEWS;

namespace GetOOFState
{
    class Program
    {
        static void Main(string[] args)
        {

            
            ExchangeServiceBinding esb = new ExchangeServiceBinding();
            esb.Url = "https://server/ews/exchange.asmx";
            esb.Credentials = new System.Net.NetworkCredential("ServiceAccount", Password", "Domain");

            esb.ExchangeImpersonation = new ExchangeImpersonationType();
            esb.ExchangeImpersonation.ConnectingSID = new ConnectingSIDType();
            esb.ExchangeImpersonation.ConnectingSID.PrimarySmtpAddress = "username@domain.com";
            

            FindItemType fit = new FindItemType();
            fit.ItemShape = new ItemResponseShapeType();
            fit.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;
            fit.Restriction = new RestrictionType();

            IsEqualToType itemMessageClass = new IsEqualToType();
            
            PathToUnindexedFieldType msgClassProp = new PathToUnindexedFieldType();
            msgClassProp.FieldURI = UnindexedFieldURIType.itemItemClass;

            ConstantValueType msgClassValue = new ConstantValueType();
            msgClassValue.Value = "IPM.Microsoft.OOF.UserOOFSettings";

            itemMessageClass.Item = msgClassProp;
            itemMessageClass.FieldURIOrConstant = new FieldURIOrConstantType();
            itemMessageClass.FieldURIOrConstant.Item = msgClassValue;
            
            
            fit.Restriction = new RestrictionType();
            fit.Restriction.Item = itemMessageClass;

            DistinguishedFolderIdType rootFolder = new DistinguishedFolderIdType();
            rootFolder.Id = DistinguishedFolderIdNameType.root;

            fit.ParentFolderIds = new BaseFolderIdType[] { rootFolder };

            FindItemResponseType firt = esb.FindItem(fit);
            string itemID = ((ArrayOfRealItemsType)((FindItemResponseMessageType)firt.ResponseMessages.Items[0]).RootFolder.Item).Items[0].ItemId.Id;

            GetItemType git = new GetItemType();
            ItemIdType iit = new ItemIdType();
            iit.Id = itemID;

            git.ItemIds = new BaseItemIdType[] { iit };

            git.ItemShape = new ItemResponseShapeType();
            git.ItemShape.BaseShape = DefaultShapeNamesType.IdOnly;

            PathToUnindexedFieldType []propsToFetch = new PathToUnindexedFieldType[1];
            propsToFetch[0] = new PathToUnindexedFieldType();
            propsToFetch[0].FieldURI = UnindexedFieldURIType.itemBody;

            git.ItemShape.AdditionalProperties = propsToFetch;
            
   

            GetItemResponseType girt = esb.GetItem(git);
            ItemType itemOOF = ((ItemType)(((ItemInfoResponseMessageType)girt.ResponseMessages.Items[0]).Items.Items[0]));

            System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
            xDoc.LoadXml(itemOOF.Body.Value);
            Console.WriteLine("OOF State: {0}", xDoc.GetElementsByTagName("OofState")[0].InnerText);
            

            

        }
    }
}

Happy Coding!!!

HOWTO: WebDAV: Send mail with Custom Form and set properties

This is going to be a very simple sample of how you can send an email with custom properties set and also change the message class so that it render on outlook as Custom Form.

Prerequisites: A custom form must be published with same class name to render the email properly.

How it works…

Step 1) It drop an email in the drafts folder of user

Step 2) Patches the properties to set Message Class & other properties, even including with special characters in name like Spaces and ‘/’

Step 3) Drop the mail to DavMailSubmissionURL to send it

Code:

 
Imports System.Net
Imports System.IO
Imports System.Web
 
Module Module1
    Const strServer As String = "Exchange_Server_Name"
    Const strMailbox As String = "Target_Mailbox"
    Const strFrom As String = "from@domain.com"
    Const strTo As String = "to@domain.com"
    Const strSubject As String = "Custom form email - sent using WebDAV"
    Const strBody As String = "<B>Hello There,</B><BR> Hope you are doing good.<BR>Good Bye!!!"
    Const strMessageClass As String = "IPM.Note.TestMessageClass"
    Const strDomain As String = "DomainNameHere"
    Const strUsername As String = "UsernameToLoginWith"
    Const strPassword As String = "Password"
 
    Dim objCDO As New CDO.Message
    Dim strMIME As String
    Dim sQuery As String = ""
 
    Dim sUri As Uri = New Uri("http://" & strServer & "/Exchange/" + strMailbox & "/Drafts/" & Guid.NewGuid().ToString() & ".eml")
    Dim sDavSubmissionURI As Uri = New Uri("http://" & strServer & "/Exchange/" + strMailbox & "/%23%23DavMailSubmissionURI%23%23/")
    Dim DavRequest As HttpWebRequest = DirectCast(WebRequest.Create(sUri), HttpWebRequest)
    Dim myCred As New NetworkCredential((strDomain & "\" & strUsername), strPassword)
    Dim myCredentialCache As New CredentialCache()
    Dim ByteQuery As Byte()
    Dim QueryStream As Stream
    Dim DavResponse As HttpWebResponse
    Dim iStatCode As Integer
    Dim sStatus As String
    Dim strm As Stream
    Dim sr As StreamReader
    Dim sText As String
 
    Sub Main()
 
        Console.WriteLine("Preparing message...")
        PrepairMessage()
 
        Console.WriteLine("Creating message in draft folder...")
        CreateMessageInDraft()
 
        Console.WriteLine("Updating message class & other properties...")
        SetMessageProperties()
 
        Console.WriteLine("Sending message...")
        SendMessage()
 
        Console.WriteLine("Message Sent")
 
 
    End Sub
 
    Sub PrepairMessage()
        With objCDO
            .From = strFrom
            .To = strTo
            .Subject = strSubject
            .HTMLBody = strBody
            strMIME = .GetStream.ReadText
        End With
 
        sQuery = strMIME
    End Sub
    Sub CreateMessageInDraft()
 
        myCredentialCache.Add(sUri, "Basic", myCred)
        DavRequest.Credentials = myCredentialCache
 
 
        DavRequest.KeepAlive = False
        DavRequest.Headers.Set("Translate", "f")
 
        DavRequest.ContentType = "message/rfc822"
        DavRequest.ContentLength = sQuery.Length
 
        'Set the request timeout to 5 minutes.
        DavRequest.Timeout = 300000
        ' Set the request method.
        DavRequest.Method = "PUT"
 
 
        ' Store the data in a byte array.
        ByteQuery = System.Text.Encoding.UTF8.GetBytes(sQuery)
        DavRequest.ContentLength = ByteQuery.Length
        QueryStream = DavRequest.GetRequestStream()
        ' write the data to be posted to the Request Stream
        QueryStream.Write(ByteQuery, 0, ByteQuery.Length)
        QueryStream.Close()
 
        QueryStream = Nothing
 
        ' Send the request and get the response.
        DavResponse = DirectCast(DavRequest.GetResponse(), HttpWebResponse)
 
 
 
        ' Get the Status code.
        iStatCode = CInt(DavResponse.StatusCode)
        sStatus = iStatCode.ToString()
        Console.WriteLine("Status Code: " & sStatus.ToString())
 
        ' Read the response stream.
        strm = DavResponse.GetResponseStream()
        sr = New StreamReader(strm)
        sText = sr.ReadToEnd()
        Console.WriteLine("Response: " & sText)
 
        ' Close the stream.
        strm.Close()
    End Sub
    Sub SetMessageProperties()
 
 
        Dim sPropPatch As String = "<?xml version=""1.0""?>" + _
        "<g:propertyupdate xmlns:g=""DAV:"">" + _
        "<g:set>" + _
        "<g:prop>" + _
        "<d:outlookmessageclass xmlns:d=""http://schemas.microsoft.com/exchange/"">" & strMessageClass & "</d:outlookmessageclass>" + _
        "<NewCustomProperty>" & "CustomProperty1" & "</NewCustomProperty>" + _
        "</g:prop>" + _
        "</g:set>" + _
        "</g:propertyupdate>"
 
        DavRequest = Nothing
        DavResponse = Nothing
 
 
        DavRequest = DirectCast(WebRequest.Create(sUri), HttpWebRequest)
        DavRequest.Credentials = myCredentialCache
 
        DavRequest.KeepAlive = False
        DavRequest.Headers.Set("Translate", "f")
 
        DavRequest.ContentType = "text/xml"
        DavRequest.ContentLength = sQuery.Length
 
        'Set the request timeout to 5 minutes.
        DavRequest.Timeout = 300000
        ' Set the request method.
        DavRequest.Method = "PROPPATCH"
 
        ' Store the data in a byte array.
        ByteQuery = System.Text.Encoding.UTF8.GetBytes(sPropPatch)
        DavRequest.ContentLength = ByteQuery.Length
        QueryStream = DavRequest.GetRequestStream()
        ' write the data to be posted to the Request Stream
        QueryStream.Write(ByteQuery, 0, ByteQuery.Length)
        QueryStream.Close()
 
        QueryStream = Nothing
 
        ' Send the request and get the response.
        DavResponse = DirectCast(DavRequest.GetResponse(), HttpWebResponse)
 
        ' Get the Status code.
        iStatCode = CInt(DavResponse.StatusCode)
        sStatus = iStatCode.ToString()
        Console.WriteLine("Status Code: " & sStatus.ToString())
 
        ' Read the response stream.
        strm = DavResponse.GetResponseStream()
        sr = New StreamReader(strm)
        sText = sr.ReadToEnd()
        Console.WriteLine("Response: " & sText)
 
        ' Close the stream.
        strm.Close()
 
 
        DavResponse = Nothing
        DavRequest = Nothing
    End Sub
    Sub SendMessage()
 
        DavRequest = Nothing
        DavResponse = Nothing
 
 
        DavRequest = DirectCast(WebRequest.Create(sUri), HttpWebRequest)
        DavRequest.Credentials = myCredentialCache
 
        'Set the request timeout to 5 minutes.
        DavRequest.Timeout = 300000
        ' Set the request method.
        DavRequest.Method = "MOVE"
        DavRequest.Headers.Add("Destination", sDavSubmissionURI.ToString())
 
        ' Send the request and get the response.
        DavResponse = DirectCast(DavRequest.GetResponse(), HttpWebResponse)
 
        ' Get the Status code.
        iStatCode = CInt(DavResponse.StatusCode)
        sStatus = iStatCode.ToString()
        Console.WriteLine("Status Code: " & sStatus.ToString())
 
        ' Read the response stream.
        strm = DavResponse.GetResponseStream()
        sr = New StreamReader(strm)
        sText = sr.ReadToEnd()
        Console.WriteLine("Response: " & sText)
 
        ' Close the stream.
        strm.Close()
 
 
        DavResponse = Nothing
        DavRequest = Nothing
 
    End Sub
 
 
End Module

Note: I will update the sample to include custom properties with special characters soon… last edited: 5/23/09 4:19 AM

Announcement: EWS Managed API launching tomorrow 04/15/09

Good news for all .Net developers working with Exchange or willing to work with Exchange but have zero experience in the domain.

Exchange Team had been working so hard to reduce your efforts and improve your efficiency.

Check out these videos to see what EWS Managed API is capable of

http://channel9.msdn.com/pdc2008/BB46/

http://msexchangeteam.com/archive/2009/03/24/450892.aspx

Keep a watch on here as it will go live in few hours, be the first one to grab it - http://msdn.microsoft.com/exchange

Searchfolder created from EWS is not displaying items falling under criteria within Outlook

I have been working on different SearchFolders cases lately where customers were trying to create SearchFolder using EWS. Working on those issues has uncovered a limitation of Outlook (I tested it on 2007, but may exist with earlier versions as well)

I created the search folder using the following XML

<?xml version="1.0"?>
<CreateFolderType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ParentFolderId xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
    <DistinguishedFolderId Id="searchfolders" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" />
  </ParentFolderId>
  <Folders xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
    <SearchFolder xmlns="http://schemas.microsoft.com/exchange/services/2006/types">
      <DisplayName>Employee Search</DisplayName>
      <SearchParameters Traversal="Deep">
        <Restriction>
          <And>
            <IsNotEqualTo>
              <ExtendedFieldURI DistinguishedPropertySetId="PublicStrings" PropertyName="EmployeeID" PropertyType="String" />
              <FieldURIOrConstant>
                <Constant Value="" />
              </FieldURIOrConstant>
            </IsNotEqualTo>
            <Exists>
              <ExtendedFieldURI DistinguishedPropertySetId="PublicStrings" PropertyName="CustomPropertyName" PropertyType="String" />
            </Exists>
          </And>
        </Restriction>
        <BaseFolderIds>
          <DistinguishedFolderId Id="inbox" />
        </BaseFolderIds>
      </SearchParameters>
    </SearchFolder>
  </Folders>                                                                  
</CreateFolderType>

I have created an email with custom property and it has some value in there to meet the criteria. The search folder is created and visible in the Outlook but I still do not see any entries under that folder. I also tried with just "Exists" criteria for the custom property but still it does not list the item. Then I created another SearchFolder with specific words in subject and itemClass = IPM.NOTE and that works fine… surprised!!

I went ahead and tried to test the Search Folder from OWA, to further add to my surprise it was not even listed in OWA… strange!! So then I dig into support.microsoft.com and found the following KB - http://support.microsoft.com/kb/831400

Symptoms: When you create Search Folders in Microsoft Office Outlook 2007 and Microsoft Office Outlook 2003in a Microsoft Exchange profile, the Search Folders do not appear in Microsoft Outlook Web Access.

Cause: This behavior occurs when you use Outlook in Cached Exchange Mode. The local copy of your mailbox maintains a Finder folder. This folder is not synchronized with the Finder folder that is in your Microsoft Exchange mailbox.

Resolution: Switch to online mode, expand search folders, let it sync with server and then you should be able to see.

I followed the resolution steps and now I can see the items in OWA & also in Outlook… relief!!

Happy Debugging…

HOW TO: Create SearchFolder to search for Custom Properties using EWS

Here is a quick sample if you are looking at creating a search folder using EWS which will look for Custom Property.

Here we are looking for a custom property named “EmployeeID” and make sure that the property exist and does not have a blank value.

public static BaseFolderType CreateCustomPropSearchFolder()
       {
           
           //Base folder type
           FolderIdType folderID = new FolderIdType();

           //create the request that will create a new searchfolder under the finder directory
           CreateFolderType folderType = new CreateFolderType();

           // inherited type from FolderType
           SearchFolderType[] folderArray = new SearchFolderType[1];

           folderArray[0] = new SearchFolderType();
           folderArray[0].SearchParameters = new SearchParametersType();

           // Go a Deep traversal and search every folder inside parent folder
           folderArray[0].SearchParameters.Traversal = SearchFolderTraversalType.Deep;        // deep traversal
           folderArray[0].SearchParameters.TraversalSpecified = true;                        // must set it to true otherwise traversal will have no effect


           //Define the base folder to search under, in this case its Inbox
           folderArray[0].SearchParameters.BaseFolderIds = new DistinguishedFolderIdType[1];
           DistinguishedFolderIdType dType = new DistinguishedFolderIdType();
           dType.Id = new DistinguishedFolderIdNameType();
           dType.Id = DistinguishedFolderIdNameType.inbox;                                    //  we are looking at Inbox only
           folderArray[0].SearchParameters.BaseFolderIds[0] = dType;


           
           folderArray[0].SearchParameters.Restriction = new RestrictionType();


           PathToExtendedFieldType CustomPropPath = new PathToExtendedFieldType();
           CustomPropPath.DistinguishedPropertySetId = DistinguishedPropertySetType.PublicStrings;
           CustomPropPath.DistinguishedPropertySetIdSpecified = true;
           CustomPropPath.PropertyName = "EmployeeID";
           CustomPropPath.PropertyType = MapiPropertyTypeType.String;

           ExistsType existsType = new ExistsType();
           existsType.Item = CustomPropPath;
           

           // First part where the 
           IsNotEqualToType isNotEqualType = new IsNotEqualToType();
           isNotEqualType.FieldURIOrConstant = new FieldURIOrConstantType();

           //Actual value of property that we are looking at
           ConstantValueType customPropertyValue = new ConstantValueType();
           customPropertyValue.Value = string.Empty;

           isNotEqualType.FieldURIOrConstant.Item = customPropertyValue;

           
           isNotEqualType.Item = CustomPropPath;
           

           // Create a AND EXPRESSION & add two condition to it
           AndType andTypeExpressions = new AndType();
           andTypeExpressions.Items = new SearchExpressionType[] {isNotEqualType,existsType };
           

           folderArray[0].SearchParameters.Restriction.Item = andTypeExpressions;
           folderArray[0].DisplayName = "Employee Search";                        // Give your search folder a unique name
           folderType.Folders = folderArray;

           TargetFolderIdType targetFolder = new TargetFolderIdType();

           //Create the searchfolder under the Finder Folder

           DistinguishedFolderIdType searchFolder = new DistinguishedFolderIdType();

           searchFolder.Id = DistinguishedFolderIdNameType.searchfolders;                    // Saving it under searchfolders root

           targetFolder.Item = searchFolder;

           folderType.ParentFolderId = targetFolder;

           // Uncomment the following lines of code to make it a hidden search folder, can be consumed by other programs and not visible to users


           // folderArray[0].ExtendedProperty = new ExtendedPropertyType[1];
           // folderArray[0].ExtendedProperty[0] = new ExtendedPropertyType();
           // folderArray[0].ExtendedProperty[0].ExtendedFieldURI = new PathToExtendedFieldType();
           // folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyTag="0x10F4";   //PR_ATTR_HIDDEN
           // folderArray[0].ExtendedProperty[0].ExtendedFieldURI.PropertyType = MapiPropertyTypeType.Boolean;
           // folderArray[0].ExtendedProperty[0].Item = "true";



           //Create the search folder
           CreateFolderResponseType createFolderResponse = esb.CreateFolder(folderType);
           //Return the newly created search folder

           FolderInfoResponseMessageType folderInfo = (FolderInfoResponseMessageType)createFolderResponse.ResponseMessages.Items[0];

           return folderInfo.Folders.Length == 0 ? null : folderInfo.Folders[0];

       }
HOWTO: Query information related to ProgID & CLSID, verify where the image is loaded from Disk.

Ever copied a DLL from one system to another and registered it using RegSvr32.exe? or in other words ever created a DLL hell situation? Its easy and dirty at the same time to copy-paste DLL between systems and register them using regsvr32.exe

Often you copy-paste, register DLL from temporary folders or may be desktop and then later delete the DLL or move to other folder without unregistering/re-registering it. Stop right there!!! You are creating a problem for yourself.

Every time you register a DLL, if its self-registering DLL, will create entries in System’s Registry with its current location, ProgID, CLSID along with other information. This information is used by programs when they are doing late binding to find the DLL and load in memory.

If you move/delete a DLL without unregistering/re-registering the DLL you are leaving with an entry behind in the Registry which is pointing to “Invalid Path”. In this case any program which is using that DLL will fail and you may not realize what’s happening.

As a first step in a “Could not load <Image>/Error loading <Image>” error scenario I would always go to registry and verify that the DLL is registered properly. It could be tedious task and risky as well. You may just edit a registry entry by mistake and break other functionality as well.

I have come up with a VBScript which gives you the ease to quickly verify the Image path & current version on the basic of ProgID or CLSID. This script will prompt you to enter either ProgID or CLSID and give you the desired information.

Here we are looking for PROGID of CDOSYS.DLL

image 

…and here are the results.

image

Similarly you could use CLSID to do reverse lookup for ProgID & Image Path

image

image

Here is the code that I used in this script…

On Error Resume Next

Dim strProgId
Dim strDescription
Dim strCLSID
Dim strInProcServer
Dim strCurVer
Dim strCurVerCLSID
Dim strCurVerInProcServer
Dim strVersionIndependentProgID

Dim oShell
Set oShell = CreateObject("WScript.Shell")

Dim strOutput

strProgId = UCase(Trim(InputBox("Enter the ProgID/CLSID:","ProgID Tool")))

If Len(strProgId)<=0 Then 
    Msgbox "Invalid ProgID/CLSID"
Else
    
    If Left(strProgId,1) = "{" Then strProgId = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strProgId & "\ProgID\")
    
    strDescription = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\")
    strCLSID = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\CLSID\")
    strCurVer = oShell.RegRead("HKEY_CLASSES_ROOT\" & strProgId & "\CurVer\")

    strInProcServer = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCLSID & "\InprocServer32\")
    strVersionIndependentProgID = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCLSID & "\VersionIndependentProgID\")
    
    strOutput = strOutput & "ProgID: " & strProgId & vbCrLf
    strOutput = strOutput & "Description: " & strDescription & vbCrLf 
    strOutput = strOutput & "Current Version: " & strCurVer & vbCrLf
    strOutput = strOutput & "VersionIndependentProgID: " & strVersionIndependentProgID & vbCrLf & vbCrLf
    
    strOutput = strOutput & strProgId & " CLSID: " & strCLSID & vbCrLf
    strOutput = strOutput & strProgId & " InProcServer: " & strInProcServer & vbCrLf & vbCrLf
    
    
    If (Len(strCurVer)>0) Then
        strCurVerCLSID = oShell.RegRead("HKEY_CLASSES_ROOT\" & strCurVer & "\CLSID\")
        strCurVerInProcServer = oShell.RegRead("HKEY_CLASSES_ROOT\CLSID\" & strCurVerCLSID & "\InprocServer32\")
        
        strOutput = strOutput & strCurVer & " CLSID: " & strCurVerCLSID & vbCrLf
        strOutput = strOutput & strCurVer & " InProcServer: " & strCurVerInProcServer & vbCrLf
    
    End If
    
    Msgbox strOutput,,"ProgId Tool"
    
End If

Happy debugging….

HOWTO: Give Service Account Access to all mailboxes on an Exchange 2007 Server

This is my first attempt to write a Powershell sample to my readers. In this sample we will give Send-As, Receive-As, ms-Exch-Store-Admin rights to an active directory user. We will be piping two commands here… Get-MailboxServer and the result will go to Add-AdPermission.

You may give same permissions using Exchange Power Shell Window

C:\>Get-MailboxServer –Identity MSGEX07 | Add-AdPermission –User UserA –AccessRights GenericRead, GenericWrite –ExtendedRights Send-As, Receive-As, ms-Exch-Store-Admin

Here is the sample…

using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;

namespace PowershellSample
{
    class Program
    {
        static void Main(string[] args)
        {
            RunspaceConfiguration config = RunspaceConfiguration.Create();
            PSSnapInException warning;

            // Load Exchange PowerShell snap-in.
            config.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out warning);
            if (warning != null) throw warning;


            using (Runspace thisRunspace = RunspaceFactory.CreateRunspace(config))
            {
                try
                {
                    thisRunspace.Open();
                    using (Pipeline thisPipeline = thisRunspace.CreatePipeline())
                    {
                        //Please change parameter values.
                        Command cmdGetMailbox = new Command("Get-MailboxServer");
                        Command cmdAddAdPermission = new Command("Add-AdPermission");

                        cmdGetMailbox.Parameters.Add("Identity", @"MSGEX07");
                        cmdAddAdPermission.Parameters.Add("User", "UserA");
                        cmdAddAdPermission.Parameters.Add("AccessRights", new string[] { "GenericRead", "GenericWrite" });
                        cmdAddAdPermission.Parameters.Add("ExtendedRights", new string[] { "Send-As", "Receive-As", "ms-Exch-Store-Admin" });

                        thisPipeline.Commands.Add(cmdGetMailbox);
                        thisPipeline.Commands.Add(cmdAddAdPermission);

                        try
                        {
                            thisPipeline.Invoke();
                        }
                        catch (Exception exx)
                        {
                            Console.Write("Error: " + exx.ToString());
                        }

                        // Check for errors in the pipeline and throw an exception if necessary.
                        if (thisPipeline.Error != null && thisPipeline.Error.Count > 0)
                        {
                            StringBuilder pipelineError = new StringBuilder();
                            pipelineError.AppendFormat("Error calling cmdLets...");
                            foreach (object item in thisPipeline.Error.ReadToEnd())
                            {
                                pipelineError.AppendFormat("{0}\n", item.ToString());
                            }

                            throw new Exception(pipelineError.ToString());
                        }
                    }
                }

                finally
                {
                    thisRunspace.Close();
                }

            }
        }
    }
}
Exchange 2007 SDK on Windows Server 2008, is it supported? YES it is!!!

I have seen lots of confusion lately and people asking this question in various forums. I do not have an official statement yet on this and waiting for a response from Exchange SDK documentation owners.

Here is my understanding, I may be wrong here.

According to http://www.microsoft.com/downloadS/details.aspx?familyid=47720D33-FA5A-4AF4-A8EB-FA39695CBAD1&displaylang=en, the Exchange 2007 SP1 SDK does not list Windows 2008 as supported platform.

It does not says it’s NOT supported but it also does not mention that whether its supported or not. Usually something which is NOT documented as “not supported” is assumed to be supported :-)

Let’s take an example of “Exchange 2007 SP1” - http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=44c66ad6-f185-4a1d-a9ab-473c1188954c

The download page does not mention that it’s supported on Windows 2008 while it is the only version of Exchange so far which is supported on Windows 2008

Source: http://technet.microsoft.com/en-us/library/bb232170.aspx

Exchange 2007 and Windows Server 2008

The RTM version of Exchange 2007 cannot be installed on Windows Server 2008. However, Exchange 2007 SP1 is supported for installation on Windows Server 2008. Although you cannot install the RTM version of Exchange 2007 on Windows Server 2008, the RTM version of Exchange 2007 will be supported for use with Windows Server 2008 directory servers.

Exchange Server 2003 Service Pack 2 (SP2) is similarly supported. Exchange Server 2003 cannot be installed on a computer running Windows Server 2008, but Exchange 2003 will be supported for use with Windows Server 2008 directory servers.

Be aware of the following when combining Microsoft Exchange with Windows Server 2008:

  • Exchange 2007 RTM and all previous versions of Microsoft Exchange are not supported for installation on a computer running Windows Server 2008.
  • Exchange 2007 SP1 can be installed on a computer running Windows Server 2008.
  • Management tools for Exchange 2007 RTM and all previous versions of Microsoft Exchange are not supported for installation on a computer running Windows Server 2008 or Windows Vista.
  • Management tools for Exchange 2007 SP1 can be installed on a computer running Windows Server 2008 or Windows Vista.

With all that into consideration, it is safe to assume that if you are running with Exchange Sp1 Management Tools on a Windows 2008 machine you are under support boundaries to install and use SDK. I will update this document once I have more information along with facts & confirmation from documentation team.

Stay tuned…

EDIT: UPDATED ON 3/18/2009

I have got confirmation from product group that its a document bug and nothing more or less. So we DO support Exchange 2007 SP1 SDK on Windows Server 2008.

More Posts Next page »
Page view tracker