Last active
January 3, 2018 16:08
-
-
Save Maverik/05223ab94115d1cc33aef7055a3efa2c to your computer and use it in GitHub Desktop.
Call Exchange Powershell Commands from C# using minimal module definitions only
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static readonly SerializationTypeConverter Converter = new SerializationTypeConverter(); | |
static readonly Command SelectSerializationDataCommand = new Command("Select-Object") { Parameters = { { "Property", "SerializationData" } } }; | |
static IEnumerable<T> ExchangeSerializerCastTo<T>(IEnumerable<object> results) => results.Where(x => Converter.CanConvertFrom(x, typeof(T))) | |
.Select(x => Converter.ConvertFrom(x, typeof(T), CultureInfo.CurrentCulture, false)) | |
.OfType<T>(); | |
void Main() | |
{ | |
var state = InitialSessionState.CreateDefault2(); | |
//Exchange2010SP3.psm1 was created using `Export-PSSession -OutputModule Exchange2010SP3 -CommandName *` command | |
//Of course you can use it with any exchange version (provided you have compatible module definition or export another one) | |
//We only need this bit to able to call commands like Get-Mailbox from the session | |
state.ImportPSModule(new[] { Path.Combine(Path.GetDirectoryName(typeof(Mailbox).Assembly.Location), "Exchange2010SP3.psm1") }); | |
using (var runspace = RunspaceFactory.CreateRunspace(state)) | |
{ | |
try | |
{ | |
runspace.Open(); | |
//Voodoo to pull error from powershell instance - otherwise things will die quietly without a trace | |
var errors = (runspace.SessionStateProxy.PSVariable.Get("Error").Value as ArrayList) | |
.OfType<ErrorRecord>() | |
.Select(x => x.Exception) | |
.ToArray(); | |
if (errors.Length > 0) | |
errors.Dump("Errors while loading module", 1); | |
using (var pipeline = runspace.CreatePipeline()) | |
{ | |
//If we wanted to pull entire exchange mailbox db, you'd leave parameters empty like in powershell - not recommended of course! | |
pipeline.Commands.Add(new Command("Get-MailBox") { Parameters = { { "Identity", "[email protected]" } } }); | |
pipeline.Commands.Add(SelectSerializationDataCommand); | |
var results = pipeline.Invoke(); | |
if (pipeline.HadErrors) | |
{ | |
pipeline.Error.ReadToEnd() | |
.OfType<PSObject>() | |
.Select(x => x.BaseObject) | |
.OfType<ErrorRecord>() | |
.Select(x => x.Exception) | |
.Dump("Errors during last invoke", 1); | |
return; | |
} | |
ExchangeSerializerCastTo<Mailbox>(results).Dump(2); | |
} | |
} | |
//We *must* close the runspace no matter what else happens otherwise we're going to run out | |
//of runspace handles on remote server and get stuck | |
finally { runspace.Close(); } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- This is the header of LINQPad save file actually while the .cs file is the rest of .linq file | |
Only broken up in here to enable syntax highlights since gist can't handle .linq files | |
The only key thing to remember: this is an AnyCPU query. This will not run in 32bit Linqpad. | |
--> | |
<Query Kind="Program"> | |
<Reference Relative="ExchangeModuleLibs\Exchange2010SP3.psm1">D:\ExchangeModuleLibs\Exchange2010SP3.psm1</Reference> | |
<Reference Relative="ExchangeModuleLibs\Microsoft.Exchange.Data.Directory.dll">D:\ExchangeModuleLibs\Microsoft.Exchange.Data.Directory.dll</Reference> | |
<Reference Relative="ExchangeModuleLibs\Microsoft.Exchange.Data.dll">D:\ExchangeModuleLibs\Microsoft.Exchange.Data.dll</Reference> | |
<GACReference>System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35</GACReference> | |
<Namespace>Microsoft.Exchange.Data</Namespace> | |
<Namespace>Microsoft.Exchange.Data.Directory.Management</Namespace> | |
<Namespace>System.Globalization</Namespace> | |
<Namespace>System.Management.Automation</Namespace> | |
<Namespace>System.Management.Automation.Runspaces</Namespace> | |
</Query> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thank you!