I have seen this question posed a lot so I decided that I would post a quick code sample here and the complete sample on my samples site.
In my sample I created a managed client and a native client which both call into a managed DLL that runs the Get-ExchangeServer cmdlet using Remote Powershell. Here is the method that actually does the work if you don't want to download the entire sample:
private const string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.Exchange"; public void GetExchangeServers(string serverName, string userName, string password, out string[] servers) {
System.Uri serverUri = new Uri(String.Format("http://{0}/powershell?serializationLevel=Full", serverName)); string[] retVal = null; System.Security.SecureString securePassword = new System.Security.SecureString(); foreach (char c in password.ToCharArray()) { securePassword.AppendChar(c); }
System.Management.Automation.PSCredential creds = new System.Management.Automation.PSCredential(userName, securePassword); RunspaceConfiguration rc = RunspaceConfiguration.Create(); WSManConnectionInfo wsManInfo = new WSManConnectionInfo(serverUri, SHELL_URI, creds);
using (Runspace rs = RunspaceFactory.CreateRunspace(wsManInfo)) { rs.Open(); PowerShell psh = PowerShell.Create(); psh.Runspace = rs; psh.AddCommand("Get-ExchangeServer");
Collection<PSObject> results = psh.Invoke();
if (psh.Streams.Error.Count > 0) { foreach (ErrorRecord err in psh.Streams.Error) { // handle the error some how } rs.Close(); servers = null; return; } retVal = new string[1];
foreach (PSObject result in results) { if (null == retVal[0] || retVal[0].Length == 0) { retVal[0] = result.Members["Name"].Value as string; } else { string[] newVal = new string[retVal.Length + 1]; retVal.CopyTo(newVal, 0); newVal[retVal.Length] = result.Members["Name"].Value as string; retVal = newVal; } } rs.Close(); } rc = null; servers = retVal; }