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


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!

Comments (3)

  1. DJ says:

    Hi, thanks your code!

    But I have got "Get-ExchangeServer is not the name of cmdlet…." error. Maybe it is some troubles when import-pssession. How to resolve it?

  2. Akashb says:

    Try building the project for x64 or "Any Configuration" in "Visual Studio"

  3. VishalJ says:

    Amazing blog, saved my atleast 20 hours 🙂 you rock Akash!!!!

Skip to main content