Using Exchange Management Shell Commands With Managed Code

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

Topic Last Modified: 2007-03-02

By Ray Dixon, Programming Writer

Would you like to add Exchange management capabilities to your Microsoft .NET Framework–based applications? This article explains the basics of using the Exchange Management Shell from managed code, and provides the building blocks from which you can add features that manage computers running Microsoft Exchange Server 2007.

How Do I Get Started?

Before you get started, you need the Windows PowerShell SDK, which is in the latest Windows Platform SDK. The Windows PowerShell SDK contains, among other things, the assembly that you must reference in order to access the Windows PowerShell or the Exchange Management Shell. For more information, see Windows PowerShell SDK.

Adding References

Add a reference to the System.Management.Automation.dll assembly. By default, this assembly is installed in C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\. After referencing the assembly, add the following directive statements to your code:

using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces

Adding the following directive statements will make it easier to work with the collections returns from the commands:

using System.Collections.Generic;
using System.Collections.ObjectModel;
Imports System.Collections.Generic
Imports System.Collections.ObjectModel

Creating and Opening a Runspace

To use the Microsoft Windows PowerShell or the Exchange Management Shell from managed code, you must first create and open a runspace. The following code creates a new instance of a runspace and then opens it.

Runspace myRunspace = RunspaceFactory.CreateRunspace();
myRunspace.Open();
Dim myRunspace As Runspace
myRunspace = RunspaceFactory.CreateRunspace()
myRunspace.Open()

This code only provides access to the cmdlets that come with the default Windows PowerShell installation. To use the cmdlets that come with the Exchange Management Shell, you must specify this by using an instance of the RunspaceConfiguration class. The following code opens a runspace that has access to the Exchange Management Shell.

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(rsConfig);
Dim rsConfig As RunspaceConfiguration
rsConfig = RunspaceConfiguration.Create()
Dim snapInException As PSSnapInException
Dim info As PSSnapInInfo
info = rsConfig.AddPSSnapIn("", snapInException)
myRunspace = RunspaceFactory.CreateRunspace(rsConfig)
myRunspace.Open()

This code specifies that you want to use Windows PowerShell in the context of the Exchange Management Shell. This gives you access to the Exchange-specific cmdlets in addition to the Windows PowerShell cmdlets.

How Do I Run a Cmdlet?

You can invoke a cmdlet from managed code in more than one way. This article explains how to use the Pipeline class to invoke a cmdlet.

First, create a new instance of the Pipeline class by using the runspace that you created. The following example shows how to create a new instance of the Pipeline class.

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(rsConfig);
Pipeline pipeLine = myRunSpace.CreatePipeline();
Dim rsConfig as RunspaceConfiguration
rsConfig = RunspaceConfiguration.Create()
Dim snapInException as PSSnapInException
Dim info as PSSnapInInfo
info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException)
Dim myRunSpace as Runspace
myRunSpace = RunspaceFactory.CreateRunspace(rsConfig)
myRunSpace.Open()
Dim pipeLine as Pipeline
pipeLine = myRunSpace.CreatePipeline()

Next, create an instance of the Command class by using the name of the cmdlet that you want to run. The following code creates an instance of the Command class that will run the Get-Command cmdlet.

Command myCommand = new Command("Get-Command");
Dim myCommand as New Command("Get-Command")

Next, add the command to the Commands collection of the pipeline.

pipeLine.Commands.Add(myCommand);
pipeLine.Commands.Add(myCommand)

Now, call the Pipeline.Invoke method to run the command.

Collection<PSObject> commandResults = pipeLine.Invoke();
Dim commandResults As Collection(Of PSObject)
commandResults = pipeLine.Invoke()

This code invokes the cmdlet(s) in the Commands collection of the pipeline and returns a collection of objects that are derived from the PSObject class. The following code puts together all of the previous code examples.

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-Command");
pipeLine.Commands.Add(myCommand);
Collection<PSObject> commandResults = pipeLine.Invoke();
Dim rsConfig as RunspaceConfiguration
rsConfig = RunspaceConfiguration.Create()
Dim snapInException As PSSnapInException
info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException)
Dim myRunSpace As Runspace
myRunSpace = RunspaceFactory.CreateRunspace(rsConfig)
myRunSpace.Open()
Dim pipeLine As Pipeline
pipeLine = myRunSpace.CreatePipeline()
Dim myCommand As New Command("Get-Command")
pipeLine.Commands.Add(myCommand)
Dim commandResults As Collection(Of PSObject)
commandResults = pipeLine.Invoke()

What Can I Do with the Results?

You can do lots of things with what the Pipeline.Invoke method returns. In this example, the collection of PSObject derived classes are available cmdlets. The first thing you can do is determine how many objects the method returned. In this case, you are invoking the pipeline in the context of the Exchange Management Shell and will get a collection that contains over 500 commands. You can get the value of the commandResults.Count property to find the exact number of commands returned. If you did not specify a runspace and used the default runspace, the collection would be much smaller because it would only contain the commands that come with Windows PowerShell. The following code shows how to invoke the same command in the default runspace.

Runspace myRunSpace = RunspaceFactory.CreateRunspace();
myRunSpace.Open();
Pipeline pipeLine = myRunSpace.CreatePipeline();
Command myCommand = new Command("Get-Command");
pipeLine.Commands.Add(myCommand);
Collection<PSObject> commandResults = pipeLine.Invoke();
Dim myRunSpace As Runspace
myRunSpace = RunspaceFactory.CreateRunspace()
myRunSpace.Open()
Dim pipeLine As Pipeline
pipeLine = myRunSpace.CreatePipeline()
Dim myCommand As New Command("Get-Command")
pipeLine.Commands.Add(myCommand)
Dim commandResults As Collection(Of PSObject)
commandResults = pipeLine.Invoke();

In this example, the value of the Count property of the commandResults collection is much smaller than the same value in the example that specifies the RunspaceConfiguration that is specific to the Exchange Management Shell.

The PSObject class has a Properties property that contains the collection of properties on the object. The following code shows how you can iterate through the commandResults collection and get the name of each cmdlet.

foreach (PSObject cmdlet in commandResults)
{
string cmdletName = cmdlet.Properties["Name"].Value.toString();
System.Diagnostics.Debug.Print(cmdletName);
}
For Each cmdlet As PSObject In commandResults
Dim cmdletName As String
cmdletName = cmdlet.Properties("Name").Value.ToString()
System.Diagnostics.Debug.Print(cmdletName)
Next

Note that in an actual application, it would be more useful to print the names to a user interface. This example prints to the trace output simply to show how you can access the properties of the objects.

How Do I Add Parameters?

Suppose you want to get a list of commands, but you want to restrict that list by using a parameter with the Get-Command cmdlet. You can do that by specifying one or more parameters and adding them to the command. The following code shows how to add a parameter so that the command restricts the list of commands that are returned to those that have "Get" as the verb.

CommandParameter verbParam = new CommandParameter("Verb","Get");
myCommand.Parameters.Add(verbParam);
Dim verbParam As New CommandParameter("Verb", "Get")
myCommand.Parameters.Add(verbParam)

You can add as many valid parameters as you like to your command. For example, suppose you want to return a list of only the Exchange Management Shell commands with the verb "Get". You can use the parameter defined in the previous example and add another parameter to the command.

CommandParameter psSnapInParam = new CommandParameter("PSSnapIn","Microsoft.Exchange.Management.PowerShell.Admin");
myCommand.Parameters.Add(psSnapInParam);
Dim psSnapInParam As New CommandParameter("PSSnapIn", "Microsoft.Exchange.Management.PowerShell.Admin")
myCommand.Parameters.Add(psSnapInParam)

If you put together the two code blocks, the command will execute using both parameters and return the Exchange Management Shell "Get" cmdlets.

How Do I Pass the Output of One Command to the Input of Another?

The pipeline is a powerful feature that is used on the command line as well as in scripts. You can also use the pipeline in your applications. To pipe the output of one command to the input of another, you simply add both commands to the pipeline. The following code gets the list of commands and then pipes that list to the Get-Member cmdlet. The result is a collection that contains every member of each command.

Runspace myRunSpace = RunspaceFactory.CreateRunspace();
myRunSpace.Open();
Pipeline pipeLine = myRunSpace.CreatePipeline();
Command getCommand = new Command("Get-Command");
pipeLine.Commands.Add(getCommand);
Command getMember = new Command("Get-Member");
pipeLine.Commands.Add(getMember);
Collection<PSObject> commandResults = pipeLine.Invoke();
Dim myRunSpace As Runspace
myRunSpace = RunspaceFactory.CreateRunspace()
myRunSpace.Open()
Dim pipeLine As Pipeline
pipeLine = myRunSpace.CreatePipeline()
Dim getCommand As New Command("Get-Command")
pipeLine.Commands.Add(getCommand)
Dim getMember As New Command("Get-Member")
pipeLine.Commands.Add(getMember)
Dim commandResults As Collection(Of PSObject)
commandResults = pipeLine.Invoke()

You can add many commands to the pipeline. They will execute in the order in which you added them, as they would from the command line, and the output of one command will be passed as the input to the next command.

Now, Go Code!

From here, you can extend the concepts to build robust, integrated applications that provide your users with an interface of your choosing. Now, get creative and go code!