locked
How do I re-establish a failed remote powershell connection or avoid leaking memory in C#

    Question

  • We are using C# code similar to following to establish a remote powershell session to manage an Exchange 2010 server:

     

    MyCode {

                System.Security.SecureString securePassword = new System.Security.SecureString();

                foreach (char c in password.ToCharArray())

                {

                    securePassword.AppendChar(c);

                }

     

                PSCredential creds = new PSCredential(userName, securePassword);

                _r = 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;

     

                _r.Open();

                powershell.Runspace = _r;

     

                Collection<PSSession> result = powershell.Invoke<PSSession>();

                foreach (ErrorRecord current in powershell.Streams.Error)

                {

                   // log errors

                }

     

                if (result.Count != 1)

                    throw new Exception("Unexpected number of Remote Runspace connections returned.");

     

                powershell = PowerShell.Create();

                command = new PSCommand();

                command.AddCommand("Set-Variable");

                command.AddParameter("Name", "ra");

                command.AddParameter("Value", result[0]);

                powershell.Commands = command;

                powershell.Runspace = _r;

                powershell.Invoke();

     

                powershell = PowerShell.Create();

                command = new PSCommand();

                command.AddScript("Import-PSSession -Session $ra");

                powershell.Commands = command;

                powershell.Runspace = _r;

                powershell.Invoke();

     

                // Wait for incoming commands, invoke as they arrive

    }

     

    This approach works fine, unless, as in a particular environment, the heartbeat mechanism between the remote powershell and the server (every 3-4 minutes, as we understand it) fails for whatever reason.  In this case, an exception is thrown trying to execute a subsequent provisioning command:  << Exception calling "PromptForCredential" with "4" argument(s): "Cannot invoke this function because the current host does not implement it." >>

     

    When this happens, we simply establish a new powershell session using the code above, and all is well, except that each time this occurs, the process eats up an additional 25-50 MB of memory.  We’ve tried calling combinations of powershell.Dispose(), powershell = null, _r.Dispose(), _r = null, System.GC.Collect() and “Remove-PSSession” to no avail.

     

    Our question, then, is twofold:  a) Is there some other way to free up the memory used by the original connection, and/or b) Is there some way to “awaken” the original powershell session when the heartbeat has failed, to avoid having to create a new session?

     

    Thanks in advance for any ideas.

    Thursday, August 26, 2010 8:30 PM