Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
ServerPowerShellDriver.cs845 linesDownload Raw Back to server
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Management.Automation.Internal;6using System.Management.Automation.Remoting;7using System.Management.Automation.Runspaces;8using System.Security.Principal;9using System.Threading;10 11using Dbg = System.Management.Automation.Diagnostics;12 13namespace System.Management.Automation14{15    /// <summary>16    /// This class wraps a PowerShell object. It is used to function17    /// as a server side powershell.18    /// </summary>19    internal class ServerPowerShellDriver20    {21        #region Private Members22 23        private bool _extraPowerShellAlreadyScheduled;24 25        // extra PowerShell at the server to be run after localPowerShell26        private readonly PowerShell _extraPowerShell;27 28        // output buffer for the local PowerShell that is associated with this powershell driver29        // associated with this powershell data structure handler object to handle all communications with the client30        private readonly PSDataCollection<PSObject> _localPowerShellOutput;31 32        // if the remaining data has been sent to the client before sending state information33        private readonly bool[] _datasent = new bool[2];34 35        // sync object for synchronizing sending data to client36        private readonly object _syncObject = new object();37 38        // there is no input when this driver was created39        private readonly bool _noInput;40        private readonly bool _addToHistory;41 42        // the server remote host instance43        // associated with this powershell44        private readonly ServerRemoteHost _remoteHost;45 46        // apartment state for this powershell47        private readonly ApartmentState apartmentState;48 49        // Handles nested invocation of PS drivers.50        private readonly IRSPDriverInvoke _psDriverInvoker;51 52        #endregion Private Members53 54        #region Constructors55 56        /// <summary>57        /// Default constructor for creating ServerPowerShellDrivers.58        /// </summary>59        /// <param name="powershell">Decoded powershell object.</param>60        /// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>61        /// <param name="noInput">Whether there is input for this powershell.</param>62        /// <param name="clientPowerShellId">The client powershell id.</param>63        /// <param name="clientRunspacePoolId">The client runspacepool id.</param>64        /// <param name="runspacePoolDriver">runspace pool driver65        /// which is creating this powershell driver</param>66        /// <param name="apartmentState">Apartment state for this powershell.</param>67        /// <param name="hostInfo">host info using which the host for68        /// this powershell will be constructed</param>69        /// <param name="streamOptions">Serialization options for the streams in this powershell.</param>70        /// <param name="addToHistory">71        /// true if the command is to be added to history list of the runspace. false, otherwise.72        /// </param>73        /// <param name="rsToUse">74        /// If not null, this Runspace will be used to invoke Powershell.75        /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.76        /// </param>77        internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,78            Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,79            ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,80            bool addToHistory, Runspace rsToUse)81            : this(powershell, extraPowerShell, noInput, clientPowerShellId, clientRunspacePoolId, runspacePoolDriver,82                   apartmentState, hostInfo, streamOptions, addToHistory, rsToUse, null)83        {84        }85 86        /// <summary>87        /// Default constructor for creating ServerPowerShellDrivers.88        /// </summary>89        /// <param name="powershell">Decoded powershell object.</param>90        /// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>91        /// <param name="noInput">Whether there is input for this powershell.</param>92        /// <param name="clientPowerShellId">The client powershell id.</param>93        /// <param name="clientRunspacePoolId">The client runspacepool id.</param>94        /// <param name="runspacePoolDriver">runspace pool driver95        /// which is creating this powershell driver</param>96        /// <param name="apartmentState">Apartment state for this powershell.</param>97        /// <param name="hostInfo">host info using which the host for98        /// this powershell will be constructed</param>99        /// <param name="streamOptions">Serialization options for the streams in this powershell.</param>100        /// <param name="addToHistory">101        /// true if the command is to be added to history list of the runspace. false, otherwise.102        /// </param>103        /// <param name="rsToUse">104        /// If not null, this Runspace will be used to invoke Powershell.105        /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.106        /// </param>107        /// <param name="output">108        /// If not null, this is used as another source of output sent to the client.109        /// </param>110        internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,111            Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,112            ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,113            bool addToHistory, Runspace rsToUse, PSDataCollection<PSObject> output)114        {115            InstanceId = clientPowerShellId;116            RunspacePoolId = clientRunspacePoolId;117            RemoteStreamOptions = streamOptions;118            this.apartmentState = apartmentState;119            LocalPowerShell = powershell;120            _extraPowerShell = extraPowerShell;121            _localPowerShellOutput = new PSDataCollection<PSObject>();122            _noInput = noInput;123            _addToHistory = addToHistory;124            _psDriverInvoker = runspacePoolDriver;125 126            DataStructureHandler = runspacePoolDriver.DataStructureHandler.CreatePowerShellDataStructureHandler(clientPowerShellId, clientRunspacePoolId, RemoteStreamOptions, LocalPowerShell);127            _remoteHost = DataStructureHandler.GetHostAssociatedWithPowerShell(hostInfo, runspacePoolDriver.ServerRemoteHost);128 129            if (!noInput)130            {131                InputCollection = new PSDataCollection<object>();132                InputCollection.ReleaseOnEnumeration = true;133                InputCollection.IdleEvent += HandleIdleEvent;134            }135 136            RegisterPipelineOutputEventHandlers(_localPowerShellOutput);137 138            if (LocalPowerShell != null)139            {140                RegisterPowerShellEventHandlers(LocalPowerShell);141                _datasent[0] = false;142            }143 144            if (extraPowerShell != null)145            {146                RegisterPowerShellEventHandlers(extraPowerShell);147                _datasent[1] = false;148            }149 150            RegisterDataStructureHandlerEventHandlers(DataStructureHandler);151 152            // set the runspace pool and invoke this powershell153            if (rsToUse != null)154            {155                LocalPowerShell.Runspace = rsToUse;156                if (extraPowerShell != null)157                {158                    extraPowerShell.Runspace = rsToUse;159                }160            }161            else162            {163                LocalPowerShell.RunspacePool = runspacePoolDriver.RunspacePool;164                if (extraPowerShell != null)165                {166                    extraPowerShell.RunspacePool = runspacePoolDriver.RunspacePool;167                }168            }169 170            if (output != null)171            {172                output.DataAdded += (sender, args) =>173                    {174                        if (_localPowerShellOutput.IsOpen)175                        {176                            var items = output.ReadAll();177                            foreach (var item in items)178                            {179                                _localPowerShellOutput.Add(item);180                            }181                        }182                    };183            }184        }185 186        #endregion Constructors187 188        #region Internal Methods189 190        /// <summary>191        /// Input collection sync object.192        /// </summary>193        internal PSDataCollection<object> InputCollection { get; }194 195        /// <summary>196        /// Local PowerShell instance.197        /// </summary>198        internal PowerShell LocalPowerShell { get; }199 200        /// <summary>201        /// Instance id by which this powershell driver is202        /// identified. This is the same as the id of the203        /// powershell on the client side.204        /// </summary>205        internal Guid InstanceId { get; }206 207        /// <summary>208        /// Serialization options for the streams in this powershell.209        /// </summary>210        internal RemoteStreamOptions RemoteStreamOptions { get; }211 212        /// <summary>213        /// Id of the runspace pool driver which created214        /// this object. This is the same as the id of215        /// the runspace pool at the client side which216        /// is associated with the powershell on the217        /// client side.218        /// </summary>219        internal Guid RunspacePoolId { get; }220 221        /// <summary>222        /// ServerPowerShellDataStructureHandler associated with this223        /// powershell driver.224        /// </summary>225        internal ServerPowerShellDataStructureHandler DataStructureHandler { get; }226 227        private PSInvocationSettings PrepInvoke(bool startMainPowerShell)228        {229            if (startMainPowerShell)230            {231                // prepare transport manager for sending and receiving data.232                DataStructureHandler.Prepare();233            }234 235            PSInvocationSettings settings = new PSInvocationSettings();236            settings.ApartmentState = apartmentState;237            settings.Host = _remoteHost;238 239            // Flow the impersonation policy to pipeline execution thread240            // only if the current thread is impersonated (Delegation is241            // also a kind of impersonation).242            if (Platform.IsWindows)243            {244                WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();245                switch (currentThreadIdentity.ImpersonationLevel)246                {247                    case TokenImpersonationLevel.Impersonation:248                    case TokenImpersonationLevel.Delegation:249                        settings.FlowImpersonationPolicy = true;250                        break;251                    default:252                        settings.FlowImpersonationPolicy = false;253                        break;254                }255            }256            else257            {258                settings.FlowImpersonationPolicy = false;259            }260 261            settings.AddToHistory = _addToHistory;262            return settings;263        }264 265        private IAsyncResult Start(bool startMainPowerShell)266        {267            PSInvocationSettings settings = PrepInvoke(startMainPowerShell);268 269            if (startMainPowerShell)270            {271                return LocalPowerShell.BeginInvoke<object, PSObject>(InputCollection, _localPowerShellOutput, settings, null, null);272            }273            else274            {275                return _extraPowerShell.BeginInvoke<object, PSObject>(InputCollection, _localPowerShellOutput, settings, null, null);276            }277        }278 279        /// <summary>280        /// Invokes the powershell asynchronously.281        /// </summary>282        internal IAsyncResult Start()283        {284            return Start(true);285        }286 287        /// <summary>288        /// Runs no command but allows the PowerShell object on the client289        /// to complete.  This is used for running "virtual" remote debug290        /// commands that sets debugger state but doesn't run any command291        /// on the server runspace.292        /// </summary>293        /// <param name="output">The output from preprocessing that we want to send to the client.</param>294        internal void RunNoOpCommand(IReadOnlyCollection<object> output)295        {296            if (LocalPowerShell != null)297            {298                System.Threading.ThreadPool.QueueUserWorkItem(299                    (state) =>300                        {301                            LocalPowerShell.SetStateChanged(302                                new PSInvocationStateInfo(303                                    PSInvocationState.Running, null));304 305                            foreach (var item in output)306                            {307                                if (item != null)308                                {309                                    _localPowerShellOutput.Add(PSObject.AsPSObject(item));310                                }311                            }312 313                            LocalPowerShell.SetStateChanged(314                                new PSInvocationStateInfo(315                                    PSInvocationState.Completed, null));316                        });317            }318        }319 320        /// <summary>321        /// Invokes the Main PowerShell object synchronously.322        /// </summary>323        internal void InvokeMain()324        {325            PSInvocationSettings settings = PrepInvoke(true);326 327            Exception ex = null;328            try329            {330                LocalPowerShell.InvokeWithDebugger(InputCollection, _localPowerShellOutput, settings, true);331            }332            catch (Exception e)333            {334                ex = e;335            }336 337            if (ex != null)338            {339                // Since this is being invoked asynchronously on a single pipeline thread340                // any invoke failures (such as possible debugger failures) need to be341                // passed back to client or the original client invoke request will not respond.342                string failedCommand = LocalPowerShell.Commands.Commands[0].CommandText;343                LocalPowerShell.Commands.Clear();344                string msg = StringUtil.Format(345                    RemotingErrorIdStrings.ServerSideNestedCommandInvokeFailed,346                    failedCommand ?? string.Empty,347                    ex.Message ?? string.Empty);348 349                LocalPowerShell.AddCommand("Write-Error").AddArgument(msg);350                LocalPowerShell.Invoke();351            }352        }353 354        #endregion Internal Methods355 356        #region Private Methods357 358        private void RegisterPowerShellEventHandlers(PowerShell powerShell)359        {360            powerShell.InvocationStateChanged += HandlePowerShellInvocationStateChanged;361 362            powerShell.Streams.Error.DataAdded += HandleErrorDataAdded;363            powerShell.Streams.Debug.DataAdded += HandleDebugAdded;364            powerShell.Streams.Verbose.DataAdded += HandleVerboseAdded;365            powerShell.Streams.Warning.DataAdded += HandleWarningAdded;366            powerShell.Streams.Progress.DataAdded += HandleProgressAdded;367            powerShell.Streams.Information.DataAdded += HandleInformationAdded;368        }369 370        private void UnregisterPowerShellEventHandlers(PowerShell powerShell)371        {372            powerShell.InvocationStateChanged -= HandlePowerShellInvocationStateChanged;373 374            powerShell.Streams.Error.DataAdded -= HandleErrorDataAdded;375            powerShell.Streams.Debug.DataAdded -= HandleDebugAdded;376            powerShell.Streams.Verbose.DataAdded -= HandleVerboseAdded;377            powerShell.Streams.Warning.DataAdded -= HandleWarningAdded;378            powerShell.Streams.Progress.DataAdded -= HandleProgressAdded;379            powerShell.Streams.Information.DataAdded -= HandleInformationAdded;380        }381 382        private void RegisterDataStructureHandlerEventHandlers(ServerPowerShellDataStructureHandler dsHandler)383        {384            dsHandler.InputEndReceived += HandleInputEndReceived;385            dsHandler.InputReceived += HandleInputReceived;386            dsHandler.StopPowerShellReceived += HandleStopReceived;387            dsHandler.HostResponseReceived += HandleHostResponseReceived;388            dsHandler.OnSessionConnected += HandleSessionConnected;389        }390 391        private void UnregisterDataStructureHandlerEventHandlers(ServerPowerShellDataStructureHandler dsHandler)392        {393            dsHandler.InputEndReceived -= HandleInputEndReceived;394            dsHandler.InputReceived -= HandleInputReceived;395            dsHandler.StopPowerShellReceived -= HandleStopReceived;396            dsHandler.HostResponseReceived -= HandleHostResponseReceived;397            dsHandler.OnSessionConnected -= HandleSessionConnected;398        }399 400        private void RegisterPipelineOutputEventHandlers(PSDataCollection<PSObject> pipelineOutput)401        {402            pipelineOutput.DataAdded += HandleOutputDataAdded;403        }404 405        private void UnregisterPipelineOutputEventHandlers(PSDataCollection<PSObject> pipelineOutput)406        {407            pipelineOutput.DataAdded -= HandleOutputDataAdded;408        }409 410        /// <summary>411        /// Handle state changed information from PowerShell412        /// and send it to the client.413        /// </summary>414        /// <param name="sender">Sender of this event.</param>415        /// <param name="eventArgs">arguments describing state changed416        /// information for this powershell</param>417        private void HandlePowerShellInvocationStateChanged(object sender,418            PSInvocationStateChangedEventArgs eventArgs)419        {420            PSInvocationState state = eventArgs.InvocationStateInfo.State;421            switch (state)422            {423                case PSInvocationState.Completed:424                case PSInvocationState.Failed:425                case PSInvocationState.Stopped:426                    {427                        if (LocalPowerShell.RunningExtraCommands)428                        {429                            // If completed successfully then allow extra commands to run.430                            if (state == PSInvocationState.Completed)431                            {432                                return;433                            }434 435                            // For failed or stopped state, extra commands cannot run and436                            // we allow this command invocation to finish.437                        }438 439                        // send the remaining data before sending in440                        // state information. This is required because441                        // the client side runspace pool will remove442                        // the association with the client side powershell443                        // once the powershell reaches a terminal state.444                        // If the association is removed, then any data445                        // sent to the powershell will be discarded by446                        // the runspace pool data structure handler on the client side447                        SendRemainingData();448 449                        if (state == PSInvocationState.Completed &&450                            (_extraPowerShell != null) &&451                            !_extraPowerShellAlreadyScheduled)452                        {453                            _extraPowerShellAlreadyScheduled = true;454                            Start(false);455                        }456                        else457                        {458                            DataStructureHandler.RaiseRemoveAssociationEvent();459 460                            // send the state change notification to the client461                            DataStructureHandler.SendStateChangedInformationToClient(462                                eventArgs.InvocationStateInfo);463 464                            UnregisterPowerShellEventHandlers(LocalPowerShell);465                            if (_extraPowerShell != null)466                            {467                                UnregisterPowerShellEventHandlers(_extraPowerShell);468                            }469 470                            UnregisterDataStructureHandlerEventHandlers(DataStructureHandler);471                            UnregisterPipelineOutputEventHandlers(_localPowerShellOutput);472 473                            // BUGBUG: currently the local powershell cannot474                            // be disposed as raising the events is475                            // not done towards the end. Need to fix476                            // powershell in order to get this enabled477                            // localPowerShell.Dispose();478                        }479                    }480 481                    break;482 483                case PSInvocationState.Stopping:484                    {485                        // abort all pending host calls486                        _remoteHost.ServerMethodExecutor.AbortAllCalls();487                    }488 489                    break;490            }491        }492 493        /// <summary>494        /// Handles DataAdded event from the Output of the powershell.495        /// </summary>496        /// <param name="sender">Sender of this information.</param>497        /// <param name="e">Arguments describing this event.</param>498        private void HandleOutputDataAdded(object sender, DataAddedEventArgs e)499        {500            int index = e.Index;501 502            lock (_syncObject)503            {504                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;505                if (!_datasent[indexIntoDataSent])506                {507                    PSObject data = _localPowerShellOutput[index];508                    // once send the output is removed so that the same509                    // is not sent again by SendRemainingData() method510                    _localPowerShellOutput.RemoveAt(index);511 512                    // send the output data to the client513                    DataStructureHandler.SendOutputDataToClient(data);514                }515            }516        }517 518        /// <summary>519        /// Handles DataAdded event from Error of the PowerShell.520        /// </summary>521        /// <param name="sender">Sender of this event.</param>522        /// <param name="e">Arguments describing this event.</param>523        private void HandleErrorDataAdded(object sender, DataAddedEventArgs e)524        {525            int index = e.Index;526 527            lock (_syncObject)528            {529                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;530                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))531                {532                    ErrorRecord errorRecord = LocalPowerShell.Streams.Error[index];533                    // once send the error record is removed so that the same534                    // is not sent again by SendRemainingData() method535                    LocalPowerShell.Streams.Error.RemoveAt(index);536 537                    // send the error record to the client538                    DataStructureHandler.SendErrorRecordToClient(errorRecord);539                }540            }541        }542 543        /// <summary>544        /// Handles DataAdded event from Progress of PowerShell.545        /// </summary>546        /// <param name="sender">Sender of this information, unused.</param>547        /// <param name="eventArgs">Arguments describing this event.</param>548        private void HandleProgressAdded(object sender, DataAddedEventArgs eventArgs)549        {550            int index = eventArgs.Index;551 552            lock (_syncObject)553            {554                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;555                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))556                {557                    ProgressRecord data = LocalPowerShell.Streams.Progress[index];558                    // once the debug message is sent, it is removed so that559                    // the same is not sent again by SendRemainingData() method560                    LocalPowerShell.Streams.Progress.RemoveAt(index);561 562                    // send the output data to the client563                    DataStructureHandler.SendProgressRecordToClient(data);564                }565            }566        }567 568        /// <summary>569        /// Handles DataAdded event from Warning of PowerShell.570        /// </summary>571        /// <param name="sender">Sender of this information, unused.</param>572        /// <param name="eventArgs">Arguments describing this event.</param>573        private void HandleWarningAdded(object sender, DataAddedEventArgs eventArgs)574        {575            int index = eventArgs.Index;576 577            lock (_syncObject)578            {579                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;580                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))581                {582                    WarningRecord data = LocalPowerShell.Streams.Warning[index];583                    // once the debug message is sent, it is removed so that584                    // the same is not sent again by SendRemainingData() method585                    LocalPowerShell.Streams.Warning.RemoveAt(index);586 587                    // send the output data to the client588                    DataStructureHandler.SendWarningRecordToClient(data);589                }590            }591        }592 593        /// <summary>594        /// Handles DataAdded from Verbose of PowerShell.595        /// </summary>596        /// <param name="sender">Sender of this information, unused.</param>597        /// <param name="eventArgs">Sender of this information.</param>598        private void HandleVerboseAdded(object sender, DataAddedEventArgs eventArgs)599        {600            int index = eventArgs.Index;601 602            lock (_syncObject)603            {604                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;605                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))606                {607                    VerboseRecord data = LocalPowerShell.Streams.Verbose[index];608                    // once the debug message is sent, it is removed so that609                    // the same is not sent again by SendRemainingData() method610                    LocalPowerShell.Streams.Verbose.RemoveAt(index);611 612                    // send the output data to the client613                    DataStructureHandler.SendVerboseRecordToClient(data);614                }615            }616        }617 618        /// <summary>619        /// Handles DataAdded from Debug of PowerShell.620        /// </summary>621        /// <param name="sender">Sender of this information, unused.</param>622        /// <param name="eventArgs">Sender of this information.</param>623        private void HandleDebugAdded(object sender, DataAddedEventArgs eventArgs)624        {625            int index = eventArgs.Index;626 627            lock (_syncObject)628            {629                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;630                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))631                {632                    DebugRecord data = LocalPowerShell.Streams.Debug[index];633                    // once the debug message is sent, it is removed so that634                    // the same is not sent again by SendRemainingData() method635                    LocalPowerShell.Streams.Debug.RemoveAt(index);636 637                    // send the output data to the client638                    DataStructureHandler.SendDebugRecordToClient(data);639                }640            }641        }642 643        /// <summary>644        /// Handles DataAdded from Information of PowerShell.645        /// </summary>646        /// <param name="sender">Sender of this information, unused.</param>647        /// <param name="eventArgs">Sender of this information.</param>648        private void HandleInformationAdded(object sender, DataAddedEventArgs eventArgs)649        {650            int index = eventArgs.Index;651 652            lock (_syncObject)653            {654                int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;655                if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))656                {657                    InformationRecord data = LocalPowerShell.Streams.Information[index];658                    // once the Information message is sent, it is removed so that659                    // the same is not sent again by SendRemainingData() method660                    LocalPowerShell.Streams.Information.RemoveAt(index);661 662                    // send the output data to the client663                    DataStructureHandler.SendInformationRecordToClient(data);664                }665            }666        }667 668        /// <summary>669        /// Send the remaining output and error information to670        /// client.671        /// </summary>672        /// <remarks>This method should be called before673        /// sending the state information. The client will674        /// remove the association between a powershell and675        /// runspace pool if it receives any of the terminal676        /// states. Hence all the remaining data should be677        /// sent before this happens. Else the data will be678        /// discarded</remarks>679        private void SendRemainingData()680        {681            int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;682            lock (_syncObject)683            {684                _datasent[indexIntoDataSent] = true;685            }686 687            try688            {689                // BUGBUG: change this code to use enumerator690                // blocked on bug #108824, to be fixed by Kriscv691                for (int i = 0; i < _localPowerShellOutput.Count; i++)692                {693                    PSObject data = _localPowerShellOutput[i];694                    DataStructureHandler.SendOutputDataToClient(data);695                }696 697                _localPowerShellOutput.Clear();698 699                // foreach (ErrorRecord errorRecord in localPowerShell.Error)700                for (int i = 0; i < LocalPowerShell.Streams.Error.Count; i++)701                {702                    ErrorRecord errorRecord = LocalPowerShell.Streams.Error[i];703                    DataStructureHandler.SendErrorRecordToClient(errorRecord);704                }705 706                LocalPowerShell.Streams.Error.Clear();707            }708            finally709            {710                lock (_syncObject)711                {712                    // reset to original state so other pipelines can stream.713                    _datasent[indexIntoDataSent] = true;714                }715            }716        }717 718        /// <summary>719        /// Stop the local powershell.720        /// </summary>721        /// <param name="sender">Sender of this event, unused.</param>722        /// <param name="eventArgs">Unused.</param>723        private void HandleStopReceived(object sender, EventArgs eventArgs)724        {725            do // false loop726            {727                if (LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped ||728                    LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Completed ||729                    LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Failed ||730                    LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Stopping)731                {732                    break;733                }734                else735                {736                    // Ensure that the local PowerShell command is not stopped in debug mode.737                    bool handledByDebugger = false;738                    if (!LocalPowerShell.IsNested &&739                        _psDriverInvoker != null)740                    {741                        handledByDebugger = _psDriverInvoker.HandleStopSignal();742                    }743 744                    if (!handledByDebugger)745                    {746                        LocalPowerShell.Stop();747                    }748                }749            } while (false);750 751            if (_extraPowerShell != null)752            {753                do // false loop754                {755                    if (_extraPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped ||756                        _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Completed ||757                        _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Failed ||758                        _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Stopping)759                    {760                        break;761                    }762                    else763                    {764                        _extraPowerShell.Stop();765                    }766                } while (false);767            }768        }769 770        /// <summary>771        /// Add input to the local powershell's input collection.772        /// </summary>773        /// <param name="sender">Sender of this event, unused.</param>774        /// <param name="eventArgs">Arguments describing this event.</param>775        private void HandleInputReceived(object sender, RemoteDataEventArgs<object> eventArgs)776        {777            // This can be called in pushed runspace scenarios for error reporting (pipeline stopped).778            // Ignore for noInput.779            if (!_noInput && (InputCollection != null))780            {781                InputCollection.Add(eventArgs.Data);782            }783        }784 785        /// <summary>786        /// Close the input collection of the local powershell.787        /// </summary>788        /// <param name="sender">Sender of this event, unused.</param>789        /// <param name="eventArgs">Arguments describing this event.</param>790        private void HandleInputEndReceived(object sender, EventArgs eventArgs)791        {792            // This can be called in pushed runspace scenarios for error reporting (pipeline stopped).793            // Ignore for noInput.794            if (!_noInput && (InputCollection != null))795            {796                InputCollection.Complete();797            }798        }799 800        private void HandleSessionConnected(object sender, EventArgs eventArgs)801        {802            // Close input if its active. no need to synchronize as input stream would have already been processed803            // when connect call came into PS plugin804 805            // TODO: Post an ETW event806            InputCollection?.Complete();807        }808 809        /// <summary>810        /// Handle a host message response received.811        /// </summary>812        /// <param name="sender">Sender of this event, unused.</param>813        /// <param name="eventArgs">Arguments describing this event.</param>814        private void HandleHostResponseReceived(object sender, RemoteDataEventArgs<RemoteHostResponse> eventArgs)815        {816            _remoteHost.ServerMethodExecutor.HandleRemoteHostResponseFromClient(eventArgs.Data);817        }818 819        /// <summary>820        /// Handles the PSDataCollection idle event.821        /// </summary>822        /// <param name="sender"></param>823        /// <param name="args"></param>824        private void HandleIdleEvent(object sender, EventArgs args)825        {826            Runspace rs = DataStructureHandler.RunspaceUsedToInvokePowerShell;827            if (rs != null)828            {829                PSLocalEventManager events = (object)rs.Events as PSLocalEventManager;830 831                if (events != null)832                {833                    foreach (PSEventSubscriber subscriber in events.Subscribers)834                    {835                        // Use the synchronous version836                        events.DrainPendingActions(subscriber);837                    }838                }839            }840        }841 842        #endregion Private Methods843    }844}845