Using C# to get to MultiValuedProperty

Today's post is to address a question we dealt with fairly recently through a customer escalation. The customer was trying to figure out the best way to programmatically get access to the entries in a MultiValuedProperty collection returned as part of an Exchange object.

Specific example we'll use here: Read in one or more mailbox objects (using Get-Mailbox cmdlet) and then iterate across and output some properties. Since we're outputting "Name" and "EmailAddresses" properties here, one will be a singleton ("Name") and one will be a collection ("EmailAddresses").

To accomplish extracting this data, immediately the customer had driven straight into the Exchange.Management namespaces looking for Mailbox. But that's not the right approach. Vivek talks about why in this blog post, but the short version is that there's nothing to be gained by tying your code directly into Exchange (no useful public methods and limited benefit from the property strong-types) and quite a bit to be lost (you become tied to the assembly version, etc).

So, how then do you do it? Well, you use PSObject and non-Exchange types everywhere. There's a pretty good starter example in Technet: https://msdn2.microsoft.com/en-us/library/bb332449.aspx

Which leads to the customer's real question -- "I can get the object, but how do I drill into the strong-type properties that are of types like MultiValuedProperty?"

Good news! MultiValuedProperty type implements ICollection, so it's actually pretty simple. When you extract the property value, just cast it as ICollection and you're golden!

Here's some sample code (based on the Technet code) with a few comments added:

    RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
    PSSnapInException snapInException = null;
    PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);
    Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
    myRunSpace.Open();

    Pipeline pipeline = myRunSpace.CreatePipeline();
    Command myCommand = new Command("Get-Mailbox");

    pipeline.Commands.Add(myCommand);

    Collection<PSObject> commandResults = pipeline.Invoke();

    // Ok, now we've got a bunch of mailboxes, cycle through them
    foreach (PSObject mailbox in commandResults)
    {
        //define which properties to get
        foreach (String propName in new string[] { "Name", "EmailAddresses" })
        {
            //grab the specified property of this mailbox
            Object objValue = mailbox.Properties[propName].Value;
            // is it a collection? "Name" isn't, but "EmailAddresses" is in this example
            if (objValue is ICollection)
            {
                ICollection collection = (ICollection)objValue;
                // Loop through each entry in the collection and output it
                foreach (object value in collection)
                {
                    Console.WriteLine(value.ToString());
                }
            }
            else
            {
                Console.WriteLine(objValue.ToString());
            }
        }
    }
    myRunSpace.Close();

Thanks to Mike Hamler for assistance with the generic solution!