Sunday, August 26, 2012

MEC from a developers perspective

The Microsoft Exchange Conference or (MEC as it is affectionately know) is being held in Orlando next month for the first time in 10 years. www.mecisback.com  . 10 years is a long time and in Technology even longer for example since the last MEC was held we have had

  • Blackberry's (started to appear around the last time MEC was held and starting to disappear now)
  • First IPhone June 2007 , ITunes and pretty much the whole Apps concept
  • First Windows Smart Phone (Pocket PC 2002)
  • Social Networking
  • FaceBook Feb. 4, 2004
  • Twitter November 4, 2008

 The term wave is used in the IT industry to convey the way in which different technologies wash through the rest of our lives and affect the way in which we work and relate to the world in general. In the later part of 2012 we are on the crest of another wave with all the following on the way or released already.
  • Windows 2012
  • Exchange 2012
  • Surface
  • Windows 8
  • IPhone 5 and Android Tablets and phones

 The great thing about technical conferences is that there are so many to choose from these days but MEC is special, because its no only just focused entirety on Exchange but because many of the sessions will be given are by the people responsible for producing and delivering the product. New products offer new work and opportunities for developers and entrepreneurs a like. MEC will really be the first and best opportunity to learn in-depth the changes and new opportunities the next version of the Exchange will give, as well as maybe learning a few things you don't know about current versions and making those important connections with your peers in the community and industry.

While like most conferences MEC is more aimed at the IT Pro rather then specifically for developers here are a few sessions any self respecting Exchange Dev shouldn't miss.

Apps for Outlook and OWA [E15.307]
 

Monday, August 13, 2012

How To Series Sample 7 : Reporting on Calendar Appointments with Attachments in EWS and Powershell

The following sample demonstrates how you can query all the calendar appointments in a Mailbox and report on those appointments that have attachments, the number of attachments on each item, attachment Size and largest attachment details.

Its uses the following AQS query to limit the result set EWS returns to only those appointments with attachments (this means the script will only run against Exchange 2010 or Exchange Online)

$AQSString = "hasattachment:true"

The script then does a batch GetItems to load all the details about attachments using the LoadPropertiesFromItems method. It then produces a report like the following

To Run the script make sure you change the following variable to the mailbox you want to run against.

$MailboxName = "user@domain.com"


I've put a downloadable copy of this script here the script itself looks like.


  1. $MailboxName = "user@domain.com"  
  2.   
  3. $rptcollection = @()  
  4. ## Load Managed API dll    
  5. Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"    
  6.    
  7. ## Set Exchange Version    
  8. $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2    
  9.    
  10. ## Create Exchange Service Object    
  11. $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)    
  12.    
  13. ## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials    
  14.    
  15. #Credentials Option 1 using UPN for the windows Account    
  16. $psCred = Get-Credential    
  17. $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())    
  18. $service.Credentials = $creds      
  19.    
  20. #Credentials Option 2    
  21. #service.UseDefaultCredentials = $true    
  22.    
  23. ## Choose to ignore any SSL Warning issues caused by Self Signed Certificates    
  24.    
  25. ## Code From http://poshcode.org/624  
  26. ## Create a compilation environment  
  27. $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider  
  28. $Compiler=$Provider.CreateCompiler()  
  29. $Params=New-Object System.CodeDom.Compiler.CompilerParameters  
  30. $Params.GenerateExecutable=$False  
  31. $Params.GenerateInMemory=$True  
  32. $Params.IncludeDebugInformation=$False  
  33. $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null  
  34.   
  35. $TASource=@' 
  36.   namespace Local.ToolkitExtensions.Net.CertificatePolicy{ 
  37.     public class TrustAll : System.Net.ICertificatePolicy { 
  38.       public TrustAll() {  
  39.       } 
  40.       public bool CheckValidationResult(System.Net.ServicePoint sp, 
  41.         System.Security.Cryptography.X509Certificates.X509Certificate cert,  
  42.         System.Net.WebRequest req, int problem) { 
  43.         return true; 
  44.       } 
  45.     } 
  46.   } 
  47. '@   
  48. $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)  
  49. $TAAssembly=$TAResults.CompiledAssembly  
  50.  
  51. ## We now create an instance of the TrustAll and attach it to the ServicePointManager  
  52. $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")  
  53. [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll  
  54.  
  55. ## end code from http://poshcode.org/624  
  56.    
  57. ## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use    
  58.    
  59. #CAS URL Option 1 Autodiscover    
  60. $service.AutodiscoverUrl($MailboxName,{$true})    
  61. "Using CAS Server : " + $Service.url     
  62.     
  63. #CAS URL Option 2 Hardcoded    
  64.    
  65. #$uri=[system.URI] "https://casservername/ews/exchange.asmx"    
  66. #$service.Url = $uri      
  67.    
  68. ## Optional section for Exchange Impersonation    
  69.    
  70. #$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)   
  71.   
  72.   
  73. $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar,$MailboxName)     
  74. $Calendar = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,$folderid)  
  75.   
  76. if($Calendar.TotalCount -gt 0){  
  77.   
  78.     $AQSString = "hasattachment:true"  
  79.     $ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)  
  80.     do{   
  81.           
  82.         $fiResults = $Calendar.findItems($AQSString,$ivItemView)    
  83.         if($fiResults.Items.Count -gt 0){  
  84.             $atAttachSet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)  
  85.             [Void]$service.LoadPropertiesForItems($fiResults,$atAttachSet)  
  86.             foreach($Item in $fiResults.Items){  
  87.                 $rptobj = "" | Select MailboxName,AppointmentSubject,DateCreated,Size,NumberOfAttachments,LargestAttachmentSize,LargestAttachmentName  
  88.                 $rptobj.MailboxName = $MailboxName  
  89.                 $rptobj.AppointmentSubject = $Item.Subject  
  90.                 $rptobj.DateCreated = $Item.DateTimeCreated   
  91.                 $rptobj.Size = [Math]::Round($Item.Size/1MB,2)  
  92.                 $rptobj.NumberOfAttachments = $Item.Attachments.Count  
  93.                 $rptobj.LargestAttachmentSize = 0  
  94.                 foreach($Attachment in $Item.Attachments){                        
  95.                     if($Attachment -is [Microsoft.Exchange.WebServices.Data.FileAttachment]){  
  96.                         $attachSize = [Math]::Round($Attachment.Size/1MB,2)  
  97.                         if($attachSize -gt $rptobj.LargestAttachmentSize){  
  98.                             $rptobj.LargestAttachmentSize = $attachSize  
  99.                             $rptobj.LargestAttachmentName = $Attachment.Name  
  100.                         }  
  101.                     }  
  102.                 }  
  103.                 $rptcollection += $rptobj  
  104.             }     
  105.         }  
  106.         $ivItemView.Offset += $fiResults.Items.Count      
  107.     }while($fiResults.MoreAvailable -eq $true)   
  108. }  
  109. $rptcollection  
  110. $rptcollection | Export-Csv -NoTypeInformation c:\temp\aptRpt.csv  


Using Custom MailTips to provide extra information in EWS

The directory functionality in Exchange Web Services can be a little limited and so within Exchange 2010 without using LDAP to access Active Directory directly there is no direct way to access custom Resource properties on Meeting Rooms or where you want to access Custom Attributes. However using Custom MailTips is one way of working around this issue (although it means duplicating the information).

For example to Create a Custom Mail Tip for a mailbox you use

set-mailbox meetingRoom2 -MailTip "Expresso Machine"

Then in EWS you can use this to retrieve the MailTip

  1. GetMailTipsType gmType = new GetMailTipsType();  
  2. gmType.MailTipsRequested = new MailTipTypes();  
  3. gmType.MailTipsRequested = MailTipTypes.CustomMailTip;  
  4. gmType.Recipients = new EmailAddressType[1];  
  5. EmailAddressType rcip1 = new EmailAddressType();  
  6. rcip1.EmailAddress = "MeetingRoom2@domain.com";  
  7. gmType.Recipients[0] = rcip1;  
  8. EmailAddressType sendAs = new EmailAddressType();  
  9. sendAs.EmailAddress = "MeetingRoom2@domain.com";  
  10. gmType.SendingAs = sendAs;  
  11.   
  12. GetMailTipsResponseMessageType gmResponse = esb.GetMailTips(gmType);  
  13. if (gmResponse.ResponseClass == ResponseClassType.Success)  
  14. {  
  15.     foreach (MailTipsResponseMessageType mtResp in gmResponse.ResponseMessages)  
  16.     {  
  17.         Console.WriteLine(mtResp.MailTips.RecipientAddress.EmailAddress);  
  18.         Console.WriteLine(mtResp.MailTips.CustomMailTip);  
  19.     }  
  20. }  


Wednesday, August 01, 2012

POX based Autodiscover clients and the Exchange 2013/Office365 preview

The big thing is the past week or so has been the release of the Exchange 2013 preview and in the cloud world the Office365 (Exchange Online 2013) preview. One of the new things in the Auto-discover response if your using one of these is the EXHTTP node that gets returned eg


I haven't quite found where this node is documented yet but if your creating Outlook Anywhere Profiles programmatically against the Office365 preview then the Server info from this node is important for building a Outlook Anywhere profile.  If your using your own POX based Auto-discover client you won't get access to this new information unless you set the UserAgent so the request looks likes its coming from Outlook.
eg

  1. String snServerName = @"https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml";  
  2. String OAProxy = "";  
  3. String OAProxy1 = "";  
  4. String ProxyCertName = "";  
  5. String ProxyCertName1 = "";  
  6. String ProfileName = "";  
  7. String InternalServerName = "";  
  8. //Do AutoDiscover  
  9.   
  10. String auDisXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006\"><Request>" +  
  11.       "<EMailAddress>" + emEmailAddress + "</EMailAddress>" +  
  12.       "<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>" +  
  13.       "</Request>" +  
  14.       "</Autodiscover>";  
  15. System.Net.HttpWebRequest adAutoDiscoRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(snServerName);  
  16. adAutoDiscoRequest.CookieContainer = new CookieContainer();  
  17. NetworkCredential ncCred = Credential;  
  18. byte[] bytes = Encoding.UTF8.GetBytes(auDisXML);  
  19. adAutoDiscoRequest.ContentLength = bytes.Length;  
  20. adAutoDiscoRequest.ContentType = "text/xml";  
  21. adAutoDiscoRequest.UserAgent = "Microsoft Office/14.0 (Windows NT 0.0; Microsoft Outlook 14.0.6112; Pro)";  
  22. adAutoDiscoRequest.Method = "POST";  
  23. adAutoDiscoRequest.Credentials = ncCred;  
  24. CookieContainer svccook = adAutoDiscoRequest.CookieContainer;  
  25. System.IO.Stream rsRequestStream = adAutoDiscoRequest.GetRequestStream();  
  26. rsRequestStream.Write(bytes, 0, bytes.Length);  
  27. rsRequestStream.Close();  
  28. adAutoDiscoRequest.AllowAutoRedirect = false;  
  29. WebResponse adResponse = adAutoDiscoRequest.GetResponse();  
  30. String Redirect = adResponse.Headers.Get("Location");  
  31. if (Redirect != null)  
  32. {  
  33.     adAutoDiscoRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(Redirect);  
  34.     adAutoDiscoRequest.ContentType = "text/xml";  
  35.     adAutoDiscoRequest.ContentLength = bytes.Length;  
  36.     adAutoDiscoRequest.Headers.Add("Depth""0");  
  37.     adAutoDiscoRequest.UserAgent = "Microsoft Office/14.0 (Windows NT 6.1; Microsoft Outlook 14.0.6112; Pro)";  
  38.     adAutoDiscoRequest.Method = "POST";  
  39.     adAutoDiscoRequest.Credentials = ncCred;  
  40.     rsRequestStream = adAutoDiscoRequest.GetRequestStream();  
  41.     rsRequestStream.Write(bytes, 0, bytes.Length);  
  42.     rsRequestStream.Close();  
  43. }  
  44. adResponse = adAutoDiscoRequest.GetResponse();  
  45. System.IO.Stream rsResponseStream = adResponse.GetResponseStream();  
  46. XmlDocument reResponseDoc = new XmlDocument();  
  47. reResponseDoc.Load(rsResponseStream);