This is a continuation of my previous post. I wanted to take a moment and discuss the intent of the sample, how to get it working, and some caveats when you attempt to take the sample and turn it into production ready code.
The purpose of the sample is to demonstrate how to use Remote Powershell from several different clients and then call an Exchange 2010 cmdlet.
There are several components that make up the sample, the RemoteExchangePS proxy DLL, the managed client and the native client.
The Native Client
The purpose of the native client is to demonstrate how to call Powershell from an unmanaged C++ application. I used COM Interop for this because it's the simplest and easiest way (in my opinion). There are a few things that you need to know about this particular component.
First, this is compiled as a x64 binary. If you are running this on a 32 bit machine you need to recompile the COM Client application in order to run it. However, before you do that you will need to also recompile the Type Library (TLB). To do that run the following at the command prompt:
Since you are now building a x86 binary you need to use the x86 version of Tlbexp.exe.
Regardless of the bitness of the binary you will need to register RemoteExchangePS.dll with COM. To do that you should run the following at the command line:
RegAsm RemoteExchangePS.DLL /codebase
I did not sign this assembly so you will receive a warning saying that you should not use the codebase switch with an unsigned assembly. Since this is only a sample you can ignore that warning. Note: You will need to use the correct RegAsm for the correct bitness of the target (i.e. if you are running this on a 32 machine you will need the 32 bit version of RegAsm).
Second, the way this sample is architected is not ideal if you are going to be calling Remote Powershell from unmanaged code over and over again. Crossing the unmanaged / managed boundary is expensive so you should make "chunky" calls and not "chatty" calls and this sample illustrates.
To actually run the sample, run the following at the command line:
ComClient.exe <SERVERNAME> <USERNAME> <PASSWORD>
The Managed Client
The managed client just demonstrates taking the input from the user and passing it to the GetExchangeServers method. You will need to supply the ServerName, UserName and Password.
This is where the magic happens. The method GetExchangeServers creates a Powershell class (which is new in .NET 2.0 and encapsulates the pieces necessary to run cmdlets). It then creates a runspace using the WsManConnectionInfo class. Local Powershell developers will note that we are not adding the Exchange snapin. You don't need it for Remote Powershell. This means this code could run anywhere whether or not the Exchange Management Tools are installed. This was not possible with Exchange 2007. It then adds the cmdlet Get-ExchangeServer by using the AddCommand method and executes the cmdlet by calling Invoke. It's at this point that the remote call is made. This is a synchronous call but you could easily make it an asynchronous call. When the call returns the code checks to see if there are any errors. If there are not then it just wraps up the names of the Exchange Servers in the organization in an array and returns it.
You can download the sample here