222 lines
10 KiB
C#
222 lines
10 KiB
C#
// <copyright file="RemotingDisconnectConnect01.cs" company="Microsoft Corporation">
|
|
// Copyright (c) 2011 Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// 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.
|
|
|
|
/// <summary>
|
|
/// This class contains the Main enrty point for the application.
|
|
/// </summary>
|
|
internal class RemotingDisconnectConnect01
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="args">This parameter is not used.</param>
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|