March, 2010

  • Akash Blogging......

    HOW TO: Call .PS1 script from Managed code using Remote Powershell(Exchange 2010)

    • 0 Comments

    As promised below is the code to call a .PS1 script and pass parameters to it. Most of the code is very similar to my previous post that showed how to call Exchange & PowerShell cmdlet.

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

    namespace CallingScriptPS
    {
    class Program
    {
    static void Main(string[] args)
    {
    string password = "Password";
    string userName = "Domain\\Administrator";
    System.Uri uri = new Uri("http://CAS-SERVER/powershell?serializationLevel=Full");
    System.Security.SecureString securePassword = String2SecureString(password);

    System.Management.Automation.PSCredential creds = new System.Management.Automation.PSCredential(userName, securePassword);

    Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();

    PowerShell powershell = PowerShell.Create();
    PSCommand command = new PSCommand();
    command.AddCommand("New-PSSession");
    command.AddParameter("ConfigurationName", "Microsoft.Exchange");
    command.AddParameter("ConnectionUri", uri);
    command.AddParameter("Credential", creds);
    command.AddParameter("Authentication", "Default");
    PSSessionOption sessionOption = new PSSessionOption();
    sessionOption.SkipCACheck = true;
    sessionOption.SkipCNCheck = true;
    sessionOption.SkipRevocationCheck = true;
    command.AddParameter("SessionOption", sessionOption);

    powershell.Commands = command;

    try
    {
    // open the remote runspace
    runspace.Open();

    // associate the runspace with powershell
    powershell.Runspace = runspace;

    // invoke the powershell to obtain the results
    Collection<PSSession> result = powershell.Invoke<PSSession>();

    foreach (ErrorRecord current in powershell.Streams.Error)
    {
    Console.WriteLine("Exception: " + current.Exception.ToString());
    Console.WriteLine("Inner Exception: " + current.Exception.InnerException);
    }

    if (result.Count != 1)
    throw new Exception("Unexpected number of Remote Runspace connections returned.");


    // Set the runspace as a local variable on the runspace
    powershell = PowerShell.Create();

    command = new PSCommand();
    command.AddCommand("Set-Variable");
    command.AddParameter("Name", "ra");
    command.AddParameter("Value", result[0]);
    powershell.Commands = command;
    powershell.Runspace = runspace;
    powershell.Invoke();



    // First import the cmdlets in the current runspace (using Import-PSSession)
    powershell = PowerShell.Create();
    command = new PSCommand();
    command.AddScript("Import-PSSession -Session $ra");
    powershell.Commands = command;
    powershell.Runspace = runspace;
    powershell.Invoke();



    // Now run get-ExchangeServer
    System.Collections.ObjectModel.Collection<PSObject> results = new System.Collections.ObjectModel.Collection<PSObject>();

    powershell = PowerShell.Create();
    powershell.Runspace = runspace;



    //Change the Path to the Script to suit your needs
    System.IO.StreamReader sr = new System.IO.StreamReader("..\\..\\Script.ps1");
    powershell.AddScript(sr.ReadToEnd());
    powershell.Runspace.SessionStateProxy.SetVariable("proc", "C*");
    powershell.Runspace.SessionStateProxy.SetVariable("mbx", "*MBX");

    results = powershell.Invoke();

    if (powershell.Streams.Error.Count > 1)
    {
    foreach (ErrorRecord er in powershell.Streams.Error)
    Console.WriteLine(er.ErrorDetails);
    }
    else
    {
    foreach (PSObject ps in results)
    {
    Console.WriteLine(ps.Properties["Name"].Value.ToString());
    }
    }
    }
    finally
    {
    // dispose the runspace and enable garbage collection
    runspace.Dispose();
    runspace = null;

    // Finally dispose the powershell and set all variables to null to free
    // up any resources.
    powershell.Dispose();
    powershell = null;
    }
    }

    private static SecureString String2SecureString(string password)
    {
    SecureString remotePassword = new SecureString();
    for (int i = 0; i < password.Length; i++)
    remotePassword.AppendChar(password[i]);

    return remotePassword;
    }

    }
    }

    Below is what the Script.PS1 looks like:

    get-process |where {$_.Name -like $proc}
    get-exchangeserver | Where {$_.Name -like $mbx}

    The two parameters that we pass in are called “proc” & “mbx”.

    Note:This code will not work if we do not call the New-PSSession & the Import-PSSession cmdlet’s for reasons explained in my previous post.

    Enjoy!

  • Akash Blogging......

    HOW TO: Migrating Exchange 2007 PowerShell Managed code to work with Exchange 2010

    • 3 Comments

    Will my Exchange 2007 PowerShell Managed code work with Exchange 2010 as is?

    Unfortunately the answer is NO, fortunately there are not many changes that you will have to make. The management experience given by Exchange 2010 through PowerShell has been moved all the way from Local to Remote. Dave Vespa has a detailed post that explains the difference between the Runspace’s.

    Only exchange cmdlets will work in this remoting scenario, you will not be able to run most of the powershell cmdlets. The powershell cmdlets that work in the remoting scenario are Out-Default, Get-FormatData, Select-Object, Measure-Object, Exit-PSSession. If you find more please do let me know...

    Yes, this does mean that you will not be able to run cmdlets like Where-Object and .PS1 scripts in the Remote Runspace. Is that a limitation? I don’t think so. We can very easily get around it by create a new Session and Importing it.

    For Exchange 2007 we had to add the Microsoft.Exchange.Management.PowerShell.Admin, now we will have to use New-PSSession and Import-PSSession and then we can do what ever we want to. Below is a code sample that shows how to use New-PSSession, Import-PSSession and using Where-Object in the now Local Runspace :

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

    namespace CallingPSCmdlet
    {
    class Program
    {
    static void Main(string[] args)
    {
    string password = "Password!";
    string userName = "Domain\\Administrator";
    System.Uri uri = new Uri("http://Exchange-Server/powershell?serializationLevel=Full");
    System.Security.SecureString securePassword = String2SecureString(password);

    PSCredential creds = new PSCredential(userName, securePassword);

    Runspace runspace = RunspaceFactory.CreateRunspace();

    PowerShell powershell = PowerShell.Create();
    PSCommand command = new PSCommand();
    command.AddCommand("New-PSSession");
    command.AddParameter("ConfigurationName", "Microsoft.Exchange");
    command.AddParameter("ConnectionUri", uri);
    command.AddParameter("Credential", creds);
    command.AddParameter("Authentication", "Default");
    PSSessionOption sessionOption = new PSSessionOption();
    sessionOption.SkipCACheck = true;
    sessionOption.SkipCNCheck = true;
    sessionOption.SkipRevocationCheck = true;
    command.AddParameter("SessionOption", sessionOption);

    powershell.Commands = command;

    try
    {
    // open the remote runspace
    runspace.Open();

    // associate the runspace with powershell
    powershell.Runspace = runspace;

    // invoke the powershell to obtain the results
    Collection<PSSession> result = powershell.Invoke<PSSession>();

    foreach (ErrorRecord current in powershell.Streams.Error)
    {
    Console.WriteLine("Exception: " + current.Exception.ToString());
    Console.WriteLine("Inner Exception: " + current.Exception.InnerException);
    }

    if (result.Count != 1)
    throw new Exception("Unexpected number of Remote Runspace connections returned.");

    // Set the runspace as a local variable on the runspace
    powershell = PowerShell.Create();
    command = new PSCommand();
    command.AddCommand("Set-Variable");
    command.AddParameter("Name", "ra");
    command.AddParameter("Value", result[0]);
    powershell.Commands = command;
    powershell.Runspace = runspace;

    powershell.Invoke();


    // First import the cmdlets in the current runspace (using Import-PSSession)
    powershell = PowerShell.Create();
    command = new PSCommand();
    command.AddScript("Import-PSSession -Session $ra");
    powershell.Commands = command;
    powershell.Runspace = runspace;
    powershell.Invoke();


    // Now run get-ExchangeServer
    powershell = PowerShell.Create();
    command = new PSCommand();
    command.AddScript("Get-ExchangeServer | where-object{$_.Name -like \"*MBX\"}");
    powershell.Commands = command;
    powershell.Runspace = runspace;

    Collection<PSObject> results = new Collection<PSObject>();
    results = powershell.Invoke();

    foreach (PSObject PSresult in results)
    {
    Console.WriteLine(PSresult.Properties["Name"].Value.ToString());
    }

    }
    finally
    {
    // dispose the runspace and enable garbage collection
    runspace.Dispose();
    runspace = null;

    // Finally dispose the powershell and set all variables to null to free
    // up any resources.
    powershell.Dispose();
    powershell = null;
    }
    }

    private static SecureString String2SecureString(string password)
    {
    SecureString remotePassword = new SecureString();
    for (int i = 0; i < password.Length; i++)
    remotePassword.AppendChar(password[i]);

    return remotePassword;
    }

    }
    }

    In my next post I will show how to call and pass parameter to a .PS1 script. Enjoy!
  • Akash Blogging......

    "Object reference not set to an instance of an object" error when trying to create object of System.Net.Mail.MailMessage

    • 0 Comments

    A few days ago I ran into an interesting problem. A customer who was trying to send a mail using System.Net.Mail was getting the error "Object reference not set to an instance of an object" when trying to create a Instance of the MailMessage class.

    Code that was failing

    MailMessage message = new MailMessage()

    The strange thing was that if I used any other variant of the constructor for MailMessage everything worked.

    Code that worked
    MailMessage message = new MailMessage("a@a.com", "a@a.com", "Test Message", "Test Message")
    MailMessage message1 = new MailMessage("a@a.com", "a@a.com")

    What could be the difference?

    Debugging the System.Net.Mail source using Visual Studio 2008 we found the following difference:
    When the default constructor is used, the below is the code for the MailMessage constructor:
    public MailMessage() {
    message = new Message();
    if(Logging.On)Logging.Associate(Logging.Web, this, message);

    // This call below is what I am talking about.
    string from = SmtpClient.MailConfiguration.Smtp.From;

    if (from != null && from.Length > 0) {
    message.From = new MailAddress(from);
    }
    }

    In the above code there is a call to read the "from" address from the mail configuration. This call is not there in any of the other constructors and therefore the other constructors work.

    What is causing "string from = SmtpClient.MailConfiguration.Smtp.From"  line to fail? The code is trying to read some setting from a configuration file. There is no web.Config or app.config file, then where is it trying to read from?

    The code tries to read from the machine.config and trying to get the mailSettings section. Is the mailSetting section not there?

    The mailSettings section was present but there was a typo in the name which the customer had accidentally made. It was typed as "mailfSettings". Correcting the spelling fixed the problem.

     
    Enjoy!
  • Akash Blogging......

    HOW TO: Read User Configuration for OWA in Exchange 2010 using EWS Managed API 1.0

    • 0 Comments

    The User Configuration operations enable clients to create, delete, retrieve, and update user configuration information. These operations are new in Exchange 2010.

    Configuration data consists of groups of related application settings. Each group of settings is stored together in separate stream properties that are set on FAI messages. The OWA configuration its stored in IPM.Configuration.OWA.UserOptions which is also a FAI message in the NON_IPM_SUBTREE.

    How do you get to the NON_IPM_SUBTREE?  NON_IPM_SUBTREE is the Parent folder of the root. Some of the properties that you can get are timezone, themeStorageId, autoaddsignature, signaturetext, navigationbarwidth, signaturehtml

    Below is a piece of sample code that retrieves the User Configuration for OWA in Exchange 2010.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Exchange.WebServices.Data;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Xml;
    using System.Collections;
    using System.Net;

    namespace ReadUserConfigurationOWA
    {
    class Program
    {
    static void Main(string[] args)
    {
    // Connect to Exchange Web Services
    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);


    //Change the Credentials to suit you needs
    service.Credentials = new WebCredentials("user", "Password", "domain");


    //Use Autodiscover or Set the URL manually. Change the email address to match yours
    service.AutodiscoverUrl("user@domain.com");

    EnumUserConfig(service);

    Console.ReadLine();
    }


    static void EnumUserConfig(ExchangeService service)
    {
    Folder Root = Folder.Bind(service, WellKnownFolderName.Root);


    UserConfiguration OWAConfiguration = UserConfiguration.Bind(service, "OWA.UserOptions", Root.ParentFolderId, UserConfigurationProperties.All);


    IDictionaryEnumerator OWAEnum = (IDictionaryEnumerator)OWAConfiguration.Dictionary.GetEnumerator();


    while (OWAEnum.MoveNext())
    {
    Console.WriteLine("Key : " + OWAEnum.Key);
    Console.WriteLine("Value : " + OWAEnum.Value);
    }
    }
    }
    }

    Enjoy!
  • Akash Blogging......

    HOW TO: Configure Exchange 2007 and Exchange 2010 for using Impersonation

    • 3 Comments

    Exchange 2010:

    Configuring Exchange Impersonation (Exchange Web Services)
    http://msdn.microsoft.com/en-us/library/bb204095.aspx

    Using Exchange Impersonation XML Request/Response
    http://msdn.microsoft.com/en-us/library/bb204088.aspx

    Using Impersonation in EWS Managed API
    http://msdn.microsoft.com/en-us/library/dd633680(EXCHG.80).aspx

    Exchange 2007:

    Configuring Exchange Impersonation (Exchange Web Services)
    http://msdn.microsoft.com/en-us/library/bb204095(EXCHG.80).aspx

    Using Exchange Impersonation (Exchange Web Services)
    http://msdn.microsoft.com/en-us/library/bb204088(EXCHG.80).aspx

    ExchangeServiceBinding Class – Code Sample
    http://msdn.microsoft.com/en-us/library/exchangewebservices.exchangeservicebinding.aspx

    Enjoy!

  • Akash Blogging......

    HOW TO: Build a complex search using SearchFilter and SearchFilterCollection in EWS Managed API 1.0

    • 2 Comments
    Here is another sample for building a complex search criteria for Finding items. We use the SearchFilter and SearchFilterCollection to build the “Restriction”. In short we are finding items which have a User Property called X-State AND the value of X-State is not (3 OR 4 OR 5) AND the ItemClass is IPM.Note.Exchange AND the mail is received after a certain date.
     
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Exchange.WebServices.Data;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Xml;

    namespace ListTopLevelFolders
    {
    class Program
    {
    static void Main(string[] args)
    {
    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);

    //Change the Credentials to suit you needs
    service.Credentials = new WebCredentials("akashb", "Password", "domain");

    //Use Autodiscover or Set the URL manually. Change the email address to match yours
    service.AutodiscoverUrl("user@domain.com");

    SearchItemsInAFolder(service);

    Console.ReadLine();
    }

    static void SearchItemsInAFolder(ExchangeService service)
    {
    // The User Property to Search
    ExtendedPropertyDefinition X_STATE =
    new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "X-STATE", MapiPropertyType.String);

    // Condition for checking if X_STATE value is 3,4,5
    List<SearchFilter> searchORFilterCollection = new List<SearchFilter>();
    searchORFilterCollection.Add(new SearchFilter.IsEqualTo(X_STATE, 3));
    searchORFilterCollection.Add(new SearchFilter.IsEqualTo(X_STATE, 4));
    searchORFilterCollection.Add(new SearchFilter.IsEqualTo(X_STATE, 5));

    //Negating the above condition. Effectively X_STATE value is NOT 3 OR 4 OR 5
    SearchFilter searchNotFilter =
    new SearchFilter.Not(new SearchFilter.SearchFilterCollection(LogicalOperator.Or, searchORFilterCollection.ToArray()));

    // AND the ItemClass is IPM.Note.Exchange
    // We create a new Search Filter collection and add a new IsEqualTo and then AND it with the
    // previous search filter.
    List<SearchFilter> searchANDFilterCollection = new List<SearchFilter>();
    searchANDFilterCollection.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.ItemClass, "IPM.Note.Exchange"));
    searchANDFilterCollection.Add(searchNotFilter);


    // X_STATE is Not 3 OR 4 OR 5 AND ItemClass is IPM.Note.Exchange
    SearchFilter searchANDFilter =
    new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchANDFilterCollection.ToArray());


    // Condition for checking if X_STATE Exists in that Item
    // AND the User Property Exists on the items.
    // We create a new Search Filter collection and add a new Exists condition and then AND it with the
    // previous search filter.
    List<SearchFilter> searchANDFilterCollection2 = new List<SearchFilter>();
    searchANDFilterCollection2.Add(new SearchFilter.Exists(X_STATE));
    searchANDFilterCollection2.Add(searchANDFilter);

    SearchFilter searchANDFilter2 = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchANDFilterCollection2.ToArray());


    // Condition for checking if the mail has been recievd before a specific time.
    // AND the mails have been received after a certain time.
    // We create a new Search Filter collection and add a new IsGreaterThan condition and then AND it with the
    // previous search filter.
    List<SearchFilter> searchANDFilterCollection3 = new List<SearchFilter>();
    searchANDFilterCollection3.Add(new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeReceived, DateTime.Parse("2010-03-01T18:30:00Z")));
    searchANDFilterCollection3.Add(searchANDFilter2);

    SearchFilter FinalsearchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchANDFilterCollection3.ToArray());


    // Create a view with a page size of 50.
    ItemView view = new ItemView(50);


    // Indicate that the base property and the User Property will be returned
    view.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, X_STATE);


    // Order the search results by the DateTimeReceived in descending order.
    view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);


    // Set the traversal to shallow. (Shallow is the default option; other options are Associated and SoftDeleted.)
    view.Traversal = ItemTraversal.Shallow;


    // Send the request to search the Inbox and get the results.
    FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, FinalsearchFilter, view);



    // Process each item.
    if (findResults.Items.Count > 0)
    {
    foreach (Item myItem in findResults.Items)
    {
    if (myItem is EmailMessage)
    {
    Console.WriteLine((myItem as EmailMessage).Subject);
    }
    if (myItem.ExtendedProperties.Count > 0)
    {
    // Display the extended property's name and property.
    foreach (ExtendedProperty extendedProperty in myItem.ExtendedProperties)
    {
    Console.WriteLine(" Extended Property Name: " + extendedProperty.PropertyDefinition.Name);
    Console.WriteLine(" Extended Property Value: " + extendedProperty.Value);
    }
    }

    }
    }
    else
    {
    Console.WriteLine("No Items Found!");
    }

    }
    }
    }


    Enjoy!
  • Akash Blogging......

    HOW TO: List Top Level Folders in a Mailbox using EWS Managed API 1.0

    • 0 Comments

    Now that developers have started using Exchange Web Services Managed API, I thought it would be nice for me to post some samples to do simple things using the API. This sample shows:

    1)How to list the Top Level folders in a mailbox.
    2)Using Paging with the FolderView class.
    3)Enabling logging of the Request and Response.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Exchange.WebServices.Data;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Xml;

    namespace ListTopLevelFolders
    {
    class Program
    {
    static void Main(string[] args)
    {
    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);

    // Enable Tracing
    service.TraceListener = new TraceListener();
    // Optional flags to indicate the requests and responses to trace.
    service.TraceFlags = TraceFlags.EwsRequest | TraceFlags.EwsResponse;
    service.TraceEnabled = true;

    //Change the Credentials to suit you needs
    service.Credentials = new WebCredentials("User", "Password", "domain");

    //Use Autodiscover or Set the URL manually. Change the email address to match yours
    service.AutodiscoverUrl("User@domain.com");

    //Uncomment to list the Top level folders
    ListTopLevelFolders(service,0);

    Console.ReadLine();
    }

    static void ListTopLevelFolders(ExchangeService service,int moffset)
    {
    int mPageSize =5;
    // Create a view with a page size of 5.
    FolderView view = new FolderView(mPageSize,moffset,OffsetBasePoint.Beginning);

    // Identify the properties to return in the results set.
    view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
    view.PropertySet.Add(FolderSchema.DisplayName);
    view.PropertySet.Add(FolderSchema.ChildFolderCount);

    // Unlike FindItem searches, folder searches can be deep traversals.
    view.Traversal = FolderTraversal.Shallow;

    // Send the request to search the mailbox and get the results.
    FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.MsgFolderRoot, view);

    // Process each item.
    foreach (Folder myFolder in findFolderResults.Folders)
    {
    if (myFolder is SearchFolder)
    {
    Console.WriteLine("Search folder: " + (myFolder as SearchFolder).DisplayName);
    }

    else if (myFolder is ContactsFolder)
    {
    Console.WriteLine("Contacts folder: " + (myFolder as ContactsFolder).DisplayName);
    }

    else if (myFolder is TasksFolder)
    {
    Console.WriteLine("Tasks folder: " + (myFolder as TasksFolder).DisplayName);
    }

    else if (myFolder is CalendarFolder)
    {
    Console.WriteLine("Calendar folder: " + (myFolder as CalendarFolder).DisplayName);
    }
    else
    {
    // Handle a generic folder.
    Console.WriteLine("Folder: " + myFolder.DisplayName);
    }
    }

    // Determine whether there are more folders to return.
    if (findFolderResults.MoreAvailable)
    {
    // Make recursive calls with offsets set for the FolderView to get the remaining folders in the result set.
    moffset = moffset + mPageSize;
    ListTopLevelFolders(service, moffset);
    }
    else
    {
    Console.WriteLine("More Available: " + findFolderResults.MoreAvailable);
    }
    }
    }

    class TraceListener : ITraceListener
    {
    #region ITraceListener Members

    public void Trace(string traceType, string traceMessage)
    {
    CreateXMLTextFile(traceType, traceMessage.ToString());
    }

    #endregion

    private void CreateXMLTextFile(string fileName, string traceContent)
    {
    // Create a new XML file for the trace information.
    try
    {
    // If the trace data is valid XML, create an XmlDocument object and save.
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(traceContent);
    xmlDoc.Save(fileName + ".xml");
    }
    catch
    {
    // If the trace data is not valid XML, save it as a text document.
    System.IO.File.WriteAllText(fileName + ".txt", traceContent);
    }
    }
    }
    }

    Enjoy!
Page 1 of 1 (7 items)