Monthly Archives: Lipiec 2014

Zarządzanie serwerem Exchange 2010/2013 poprzez Exchange Management Shell

2014-07-20

W jednym z poprzednich tematów opisałem sposób zarządzania serwerem Exchange 2007 poprzez polecenia PowerShell (tzw. cmdlets) wywoływane z poziomu .NET. Jeżeli tego samego rozwiązania chcielibyśmy użyć do obsługi serwerów Exchange 2010/2013 musimy nieco zmodyfikować nasz kod. W tych wersjach Exchange korzystanie ze środowiska Exchange Management Shell odbywa się poprzez zdalne sesje PowerShell (PowerShell remoting), a nie tak jak wcześniej przez załadowanie odpowiedniego PSSnapIn. Istnieje co prawda możliwość wykorzystania PSSnapIn „Microsoft.Exchange.Management.PowerShell.E2010” ale jest to metoda niezalecana. W przypadku Exchange 2010/2013 kod metody InvokeCommand (zamieszczonej we wspomnianym wcześniej wpisie) powinien wyglądać tak:

public void InvokeCommand(
	string exchangeEndpointUri,
	string command,
	Dictionary<string, object> parameters,
	out List<Dictionary<string, string>> results,
	out List<string> errors)
{
	results = new List<Dictionary<string, string>>();
	errors = new List<string>();

	var connectionInfo = new WSManConnectionInfo(
		new Uri(exchangeEndpointUri),
		"http://schemas.microsoft.com/powershell/Microsoft.Exchange",
		(PSCredential)null);
	connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
	connectionInfo.SkipCACheck = true;
	connectionInfo.SkipCNCheck = true;

	using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(connectionInfo))
	{
		myRunSpace.Open();
		using (PowerShell powershell = PowerShell.Create())
		{
			powershell.Runspace = myRunSpace;
			powershell.AddCommand(command);
			powershell.AddParameters(parameters);

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

			if (powershell.Streams.Error != null && powershell.Streams.Error.Count > 0)
				foreach (ErrorRecord error in powershell.Streams.Error)
					errors.Add(error.ToString());

			if (commandResults != null)
				foreach (PSObject commandResult in commandResults)
				{
					var result = new Dictionary<string, string>();
					foreach (PSPropertyInfo property in commandResult.Properties)
					{
						string propertyName = property.Name;
						string propertyValue = property.Value == null ? "" : property.Value.ToString();

						result.Add(propertyName, propertyValue);
					}
					results.Add(result);
				}
		}
		myRunSpace.Close();
	}
}

Główna zmiana polega na wykorzystaniu klasy WSManConnectionInfo do połączenia z serwerem Exchange (wymagane jest podanie adresu serwera oraz w przypadku uwierzytelniania konkretnym użytkownikiem – obiektu PSCredential). Poprzednio do tego celu używany był odpowiedni plik PSSnapIn ładowany za pomocą metody RunspaceConfiguration.AddPSSnapIn. W powyższej metodzie do wywoływania poleceń cmdlet zastosowałem klasę PowerShell, ale można wykorzystać poprzednio użyte klasy Pipeline i Command. Największą zaletą nowego podejścia jest fakt, że nasz kod możemy teraz uruchomić na dowolnej maszynie mogącej połączyć się z serwerem Exchange 2010/2013.