// // Copyright (c) 2011 Microsoft Corporation. All rights reserved. // // DISCLAIMER OF WARRANTY: The software is licensed “as-is.” You // bear the risk of using it. Microsoft gives no express warranties, // guarantees or conditions. You may have additional consumer rights // under your local laws which this agreement cannot change. To the extent // permitted under your local laws, Microsoft excludes the implied warranties // of merchantability, fitness for a particular purpose and non-infringement. namespace Microsoft.Samples.PowerShell.Runspaces { using System; using System.Threading; using System.Management.Automation; // Windows PowerShell namespace. using System.Management.Automation.Runspaces; // Windows PowerShell namespace. /// /// This class contains the Main enrty point for the application. /// internal class RemotingDisconnectConnect01 { /// /// This sample shows how to use the PowerShell Runspace and Pipeline classes to /// start a long running script on a remote server, disconnect from the server /// while the script continues to run, and then reconnect to the server to obtain /// status information on the running script and to retrieve output data. /// /// This parameter is not used. public static void Main(string[] args) { RunspaceState rsState = RunspaceState.BeforeOpen; PipelineState plState = PipelineState.NotStarted; // Create the connection object that defines a WSMan/WinRM connection. // The default constructor will create a WSMan connection object for // the localhost. WSManConnectionInfo connectionInfo = new WSManConnectionInfo(); // // Scenario 1 // // In this scenario a remote runspace object and a pipeline object are created to // invoke a long running script on the remote (localhost) server. // While the script is running the remoterunspace and pipeline objects are // disconnected. The same remote runspace and pipeline objects are then // *reconnected* here to the (localhost) server to obtain status information and // output data generated by the script. // // Create a remote runspace with the connection information. using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo)) { // Open the remote runspace, which will establish the connection. runspace.Open(); // Create a pipeline object to run a "long running" PowerShell script // that will run for 60 seconds and output data. using (Pipeline pipeline = runspace.CreatePipeline(@"1..60 | foreach {sleep 1; 'Output ' + $_}")) { // Start the script running in a remote session on the localhost. This // is an asynchronous invoke so the call will return immediately while // the script runs in the remote session. pipeline.InvokeAsync(); // Let the script run for a while. Thread.Sleep(2000); // Disconnect the runspace and pipeline objects. The script continues to // run in the remote (localhost) session. runspace.Disconnect(); // Check that the runspace object is disconnected. rsState = runspace.RunspaceStateInfo.State; // Check that the pipeline object is disconnected. plState = pipeline.PipelineStateInfo.State; // Let the script run on the server for a while. Thread.Sleep(2000); // Reconnect the pipeline back to the server asynchronously. This call will return // immediately and the status of the running script can be checked. Note that the // associated runspace object is also reconnected implicitly. pipeline.ConnectAsync(); // Allow time for connection operation to complete. Thread.Sleep(2000); // Check that the runspace object is reconnected (Opened state). rsState = runspace.RunspaceStateInfo.State; // Check that the pipeline object is reconnected and running. plState = pipeline.PipelineStateInfo.State; // Get all available output from the pipeline, and continue getting output data // until the pipeline running script completes. while (!pipeline.Output.EndOfPipeline) { pipeline.Output.WaitHandle.WaitOne(); while (pipeline.Output.Count > 0) { PSObject psObject = pipeline.Output.Read(); // Write output object data. Console.WriteLine(psObject.ToString()); } } } } // // Scenario 2 // // In this scenario a new pipeline object is created on the runspace and the // same long running script is invoked. Again the remote runspace and pipeline // objects are disconnected while the script runs on the localhost. // This time we will dispose the remote runspace and pipeline objects while they // are in the disconnected state. The remote runspace and pipeline objects are // then *reconstructed* based on information from the localhost remote session. // The remote runspace and pipeline objects are connected to the server to obtain // status information and output data from the running command. // Guid runspaceInstanceId; // Create a remote runspace with the connection information. using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo)) { // Open the remote runspace, which will establish the connection. runspace.Open(); // Save the runspace instance Id for later referral. runspaceInstanceId = runspace.InstanceId; // Create a script pipeline. using (Pipeline pipeline = runspace.CreatePipeline(@"1..60 | foreach {sleep 1; 'Output ' + $_}")) { // Start the script running on the (localhost) server. pipeline.InvokeAsync(); // Let the script run for a while. Thread.Sleep(2000); // Disconnect the remote runspace and pipeline objects. The script continues to // run on the (localhost) server. runspace.Disconnect(); // Check that the runspace object is disconnected. rsState = runspace.RunspaceStateInfo.State; // Check that the pipeline object is disconnected. plState = pipeline.PipelineStateInfo.State; // Let the script run on the server for a while. Thread.Sleep(2000); } } // Both the runspace and pipeline objects are disconnected from this PowerShell // client but still running in the remote session. We can reconstruct new // client runspace and pipeline objects from the original runspace instance Id, // which uniquely identifies the disconnected session running on the localhost. // Query the localhost server for runspaces with running script/commands. Runspace runspace1 = null; Runspace[] runspaces = Runspace.GetRunspaces(connectionInfo); foreach (Runspace rs in runspaces) { if (rs.InstanceId == runspaceInstanceId) { runspace1 = rs; break; } } if (runspace1 != null) { // This is a new runspace object in the Disconnected state that contains information // about the script running in this runspace on the remote session. using (runspace1) { // Create a new pipeline object for the script running on the server in this runspace. // The pipeline object is created in a disconnected state. using (Pipeline pipeline = runspace1.CreateDisconnectedPipeline()) { // Check the state of the pipeline. plState = pipeline.PipelineStateInfo.State; // Connect the pipeline object asynchronously. // Note that this method also connects the runspace implicitly. pipeline.ConnectAsync(); // Allow time for connection operation to complete. Thread.Sleep(2000); // Check that the runspace is connected and in the Opened state. rsState = runspace1.RunspaceStateInfo.State; // Check that the pipeline object is reconnected and running. plState = pipeline.PipelineStateInfo.State; // Get all available output from the pipeline, and continue getting output data // until the pipeline script completes. while (!pipeline.Output.EndOfPipeline) { pipeline.Output.WaitHandle.WaitOne(); while (pipeline.Output.Count > 0) { PSObject psObject = pipeline.Output.Read(); // Write output object data. Console.WriteLine(psObject.ToString()); } } } } } } } }