Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ClientRemotePowerShell.cs1001 linesDownload Raw Back to client
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Management.Automation.Host;7using System.Management.Automation.Internal;8using System.Management.Automation.Remoting;9 10using Dbg = System.Management.Automation.Diagnostics;11 12namespace System.Management.Automation.Runspaces.Internal13{14    /// <summary>15    /// PowerShell client side proxy base which handles invocation16    /// of powershell on a remote machine.17    /// </summary>18    internal sealed class ClientRemotePowerShell : IDisposable19    {20        #region Tracer21 22        [TraceSource("CRPS", "ClientRemotePowerShell")]23        private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("CRPS", "ClientRemotePowerShellBase");24 25        #endregion Tracer26 27        #region Constructors28 29        /// <summary>30        /// Constructor which creates a client remote powershell.31        /// </summary>32        /// <param name="shell">Powershell instance.</param>33        /// <param name="runspacePool">The runspace pool associated with34        /// this shell</param>35        internal ClientRemotePowerShell(PowerShell shell, RemoteRunspacePoolInternal runspacePool)36        {37            this.shell = shell;38            clientRunspacePoolId = runspacePool.InstanceId;39            this.runspacePool = runspacePool;40 41            // retrieve the computer name from the runspacepool42            // information so that it can be used in adding43            // warning to host messages44            computerName = runspacePool.ConnectionInfo.ComputerName;45        }46 47        #endregion Constructors48 49        #region Internal Methods/Properties50 51        /// <summary>52        /// Instance Id associated with this53        /// client remote powershell.54        /// </summary>55        internal Guid InstanceId56        {57            get58            {59                return PowerShell.InstanceId;60            }61        }62 63        /// <summary>64        /// PowerShell associated with this ClientRemotePowerShell.65        /// </summary>66        internal PowerShell PowerShell67        {68            get69            {70                return shell;71            }72        }73 74        /// <summary>75        /// Set the state information of the client powershell.76        /// </summary>77        /// <param name="stateInfo">State information to set.</param>78        internal void SetStateInfo(PSInvocationStateInfo stateInfo)79        {80            shell.SetStateChanged(stateInfo);81        }82 83        /// <summary>84        /// Whether input is available when this object is created.85        /// </summary>86        internal bool NoInput87        {88            get89            {90                return noInput;91            }92        }93 94        /// <summary>95        /// Input stream associated with this object.96        /// </summary>97        internal ObjectStreamBase InputStream98        {99            get100            {101                return inputstream;102            }103 104            set105            {106                inputstream = value;107 108                if (inputstream != null && (inputstream.IsOpen || inputstream.Count > 0))109                {110                    noInput = false;111                }112                else113                {114                    noInput = true;115                }116            }117        }118 119        /// <summary>120        /// Output stream associated with this object.121        /// </summary>122        internal ObjectStreamBase OutputStream123        {124            get125            {126                return outputstream;127            }128 129            set130            {131                outputstream = value;132            }133        }134 135        /// <summary>136        /// Data structure handler object.137        /// </summary>138        internal ClientPowerShellDataStructureHandler DataStructureHandler139        {140            get141            {142                return dataStructureHandler;143            }144        }145 146        /// <summary>147        /// Invocation settings associated with this148        /// ClientRemotePowerShell.149        /// </summary>150        internal PSInvocationSettings Settings151        {152            get153            {154                return settings;155            }156        }157 158        /// <summary>159        /// Close the output, error and other collections160        /// associated with the shell, so that the161        /// enumerator does not block.162        /// </summary>163        internal void UnblockCollections()164        {165            shell.ClearRemotePowerShell();166 167            outputstream.Close();168            errorstream.Close();169            inputstream?.Close();170        }171 172        /// <summary>173        /// Stop the remote powershell asynchronously.174        /// </summary>175        /// <remarks>This method will be called from176        /// within the lock on PowerShell. Hence no need177        /// to lock</remarks>178        internal void StopAsync()179        {180            // If we are in robust connection retry mode then auto-disconnect this command181            // rather than try to stop it.182            PSConnectionRetryStatus retryStatus = _connectionRetryStatus;183            if ((retryStatus == PSConnectionRetryStatus.NetworkFailureDetected ||184                 retryStatus == PSConnectionRetryStatus.ConnectionRetryAttempt) &&185                this.runspacePool.RunspacePoolStateInfo.State == RunspacePoolState.Opened)186            {187                // While in robust connection retry mode, this call forces robust connections188                // to abort retries and go directly to auto-disconnect.189                this.runspacePool.BeginDisconnect(null, null);190                return;191            }192 193            // PowerShell CoreStop would have handled cases194            // for NotStarted, Stopping and already Stopped195            // so at this point, there is no need to make any196            // check. The message simply needs to be sent197            // across to the server198            stopCalled = true;199            dataStructureHandler.SendStopPowerShellMessage();200        }201 202        /// <summary>203        /// </summary>204        internal void SendInput()205        {206            dataStructureHandler.SendInput(this.inputstream);207        }208 209        /// <summary>210        /// This event is raised, when a host call is for a remote pipeline211        /// which this remote powershell wraps.212        /// </summary>213        internal event EventHandler<RemoteDataEventArgs<RemoteHostCall>> HostCallReceived;214 215        /// <summary>216        /// Initialize the client remote powershell instance.217        /// </summary>218        /// <param name="inputstream">Input for execution.</param>219        /// <param name="errorstream">error stream to which220        /// data needs to be written to</param>221        /// <param name="informationalBuffers">informational buffers222        /// which will hold debug, verbose and warning messages</param>223        /// <param name="settings">settings based on which this powershell224        /// needs to be executed</param>225        /// <param name="outputstream">output stream to which data226        /// needs to be written to</param>227        internal void Initialize(228            ObjectStreamBase inputstream, ObjectStreamBase outputstream,229                 ObjectStreamBase errorstream, PSInformationalBuffers informationalBuffers,230                        PSInvocationSettings settings)231        {232            initialized = true;233            this.informationalBuffers = informationalBuffers;234            InputStream = inputstream;235            this.errorstream = errorstream;236            this.outputstream = outputstream;237            this.settings = settings;238 239            if (settings == null || settings.Host == null)240            {241                hostToUse = runspacePool.Host;242            }243            else244            {245                hostToUse = settings.Host;246            }247 248            dataStructureHandler = runspacePool.DataStructureHandler.CreatePowerShellDataStructureHandler(this);249 250            // register for events from the data structure handler251            dataStructureHandler.InvocationStateInfoReceived += HandleInvocationStateInfoReceived;252            dataStructureHandler.OutputReceived += HandleOutputReceived;253            dataStructureHandler.ErrorReceived += HandleErrorReceived;254            dataStructureHandler.InformationalMessageReceived += HandleInformationalMessageReceived;255            dataStructureHandler.HostCallReceived += HandleHostCallReceived;256            dataStructureHandler.ClosedNotificationFromRunspacePool += HandleCloseNotificationFromRunspacePool;257            dataStructureHandler.BrokenNotificationFromRunspacePool += HandleBrokenNotificationFromRunspacePool;258            dataStructureHandler.ConnectCompleted += HandleConnectCompleted;259            dataStructureHandler.ReconnectCompleted += HandleConnectCompleted;260            dataStructureHandler.RobustConnectionNotification += HandleRobustConnectionNotification;261            dataStructureHandler.CloseCompleted += HandleCloseCompleted;262        }263 264        /// <summary>265        /// Do any clean up operation per initialization here.266        /// </summary>267        internal void Clear()268        {269            initialized = false;270        }271 272        /// <summary>273        /// If this client remote powershell has been initialized.274        /// </summary>275        internal bool Initialized276        {277            get278            {279                return initialized;280            }281        }282 283        /// <summary>284        /// </summary>285        /// <param name="sender"></param>286        /// <param name="eventArgs"></param>287        internal static void ExitHandler(object sender, RemoteDataEventArgs<RemoteHostCall> eventArgs)288        {289            RemoteHostCall hostcall = eventArgs.Data;290 291            if (hostcall.IsSetShouldExitOrPopRunspace)292            {293                return;294            }295 296            // use the method from the RemotePowerShell to indeed execute this call297            ClientRemotePowerShell remotePowerShell = (ClientRemotePowerShell)sender;298 299            remotePowerShell.ExecuteHostCall(hostcall);300        }301 302        /// <summary>303        /// Attempts to reconnect or connect to a running command on a remote server,304        /// which will resume events and data collection from the server.305        /// If connectCmdInfo parameter is null then a reconnection is attempted and306        /// it is assumed that the current client state is unchanged since disconnection.307        /// If connectCmdInfo parameter is non-null then a connection is attempted to308        /// the specified remote running command.309        /// This is an asynchronous call and results will be reported in the ReconnectCompleted310        /// or the ConnectCompleted call back as appropriate.311        /// </summary>312        /// <param name="connectCmdInfo">ConnectCommandInfo specifying remote command.</param>313        internal void ConnectAsync(ConnectCommandInfo connectCmdInfo)314        {315            if (connectCmdInfo == null)316            {317                // Attempt to do a reconnect with the current PSRP client state.318                this.dataStructureHandler.ReconnectAsync();319            }320            else321            {322                // First add this command DS handler to the remote runspace pool list.323                Dbg.Assert(this.shell.RunspacePool != null, "Invalid runspace pool for this powershell object.");324                this.shell.RunspacePool.RemoteRunspacePoolInternal.AddRemotePowerShellDSHandler(325                                            this.InstanceId, this.dataStructureHandler);326 327                // Now do the asynchronous connect.328                this.dataStructureHandler.ConnectAsync();329            }330        }331 332        /// <summary>333        /// This event is fired when this PowerShell object receives a robust connection334        /// notification from the transport.335        /// </summary>336        internal event EventHandler<PSConnectionRetryStatusEventArgs> RCConnectionNotification;337 338        /// <summary>339        /// Current remote connection retry status.340        /// </summary>341        internal PSConnectionRetryStatus ConnectionRetryStatus342        {343            get { return _connectionRetryStatus; }344        }345 346        #endregion Internal Methods/Properties347 348        #region Private Methods349 350        /// <summary>351        /// An error record is received from the powershell at the352        /// server side. It is added to the error collection of the353        /// client powershell.354        /// </summary>355        /// <param name="sender">Sender of this event, unused.</param>356        /// <param name="eventArgs">Arguments describing this event.</param>357        private void HandleErrorReceived(object sender, RemoteDataEventArgs<ErrorRecord> eventArgs)358        {359            using (s_tracer.TraceEventHandlers())360            {361                shell.SetHadErrors(true);362                errorstream.Write(eventArgs.Data);363            }364        }365 366        /// <summary>367        /// An output object is received from the powershell at the368        /// server side. It is added to the output collection of the369        /// client powershell.370        /// </summary>371        /// <param name="sender">Sender of this event, unused.</param>372        /// <param name="eventArgs">Arguments describing this event.</param>373        private void HandleOutputReceived(object sender, RemoteDataEventArgs<object> eventArgs)374        {375            using (s_tracer.TraceEventHandlers())376            {377                object data = eventArgs.Data;378 379                try380                {381                    outputstream.Write(data);382                }383                catch (PSInvalidCastException e)384                {385                    shell.SetStateChanged(new PSInvocationStateInfo(PSInvocationState.Failed, e));386                }387            }388        }389 390        /// <summary>391        /// The invocation state of the server powershell has changed.392        /// The state of the client powershell is reflected accordingly.393        /// </summary>394        /// <param name="sender">Sender of this event, unused.</param>395        /// <param name="eventArgs">Arguments describing this event.</param>396        private void HandleInvocationStateInfoReceived(object sender,397            RemoteDataEventArgs<PSInvocationStateInfo> eventArgs)398        {399            using (s_tracer.TraceEventHandlers())400            {401                PSInvocationStateInfo stateInfo = eventArgs.Data;402 403                // we should not receive any transient state from404                // the server405                Dbg.Assert(!(stateInfo.State == PSInvocationState.Running ||406                           stateInfo.State == PSInvocationState.Stopping),407                           "Transient states should not be received from the server");408 409                if (stateInfo.State == PSInvocationState.Disconnected)410                {411                    SetStateInfo(stateInfo);412                }413                else if (stateInfo.State == PSInvocationState.Stopped ||414                         stateInfo.State == PSInvocationState.Failed ||415                         stateInfo.State == PSInvocationState.Completed)416                {417                    // Special case for failure error due to ErrorCode==-2144108453 (no ShellId found).418                    // In this case terminate session since there is no longer a shell to communicate419                    // with.420                    bool terminateSession = false;421                    if (stateInfo.State == PSInvocationState.Failed)422                    {423                        PSRemotingTransportException remotingTransportException = stateInfo.Reason as PSRemotingTransportException;424                        terminateSession = (remotingTransportException != null) &&425                                           (remotingTransportException.ErrorCode == System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_TARGETSESSION_DOESNOTEXIST);426                    }427 428                    // if state is completed or failed or stopped,429                    // then the collections need to be closed as430                    // well, else the enumerator will block431                    UnblockCollections();432 433                    if (stopCalled || terminateSession)434                    {435                        // Reset stop called flag.436                        stopCalled = false;437 438                        // if a Stop method has been called, then powershell439                        // would have already raised a Stopping event, after440                        // which only a Stopped should be raised441                        _stateInfoQueue.Enqueue(new PSInvocationStateInfo(PSInvocationState.Stopped,442                            stateInfo.Reason));443 444                        // If the stop call failed due to network problems then close the runspace445                        // since it is now unusable.446                        CheckAndCloseRunspaceAfterStop(stateInfo.Reason);447                    }448                    else449                    {450                        _stateInfoQueue.Enqueue(stateInfo);451                    }452                    // calling close async only after making sure all the internal members are prepared453                    // to handle close complete.454                    dataStructureHandler.CloseConnectionAsync(null);455                }456            }457        }458 459        /// <summary>460        /// Helper method to check any error condition after a stop call461        /// and close the remote runspace/pool if the stop call failed due462        /// to network outage problems.463        /// </summary>464        /// <param name="ex">Exception.</param>465        private void CheckAndCloseRunspaceAfterStop(Exception ex)466        {467            PSRemotingTransportException transportException = ex as PSRemotingTransportException;468            if (transportException != null &&469                (transportException.ErrorCode == System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_SENDDATA_CANNOT_CONNECT ||470                 transportException.ErrorCode == System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_SENDDATA_CANNOT_COMPLETE ||471                 transportException.ErrorCode == System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_TARGETSESSION_DOESNOTEXIST))472            {473                object rsObject = shell.GetRunspaceConnection();474                if (rsObject is Runspace)475                {476                    Runspace runspace = (Runspace)rsObject;477                    if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)478                    {479                        try480                        {481                            runspace.Close();482                        }483                        catch (PSRemotingTransportException)484                        { }485                    }486                }487                else if (rsObject is RunspacePool)488                {489                    RunspacePool runspacePool = (RunspacePool)rsObject;490                    if (runspacePool.RunspacePoolStateInfo.State == RunspacePoolState.Opened)491                    {492                        try493                        {494                            runspacePool.Close();495                        }496                        catch (PSRemotingTransportException)497                        { }498                    }499                }500            }501        }502 503        /// <summary>504        /// Handler for handling any informational message received505        /// from the server side.506        /// </summary>507        /// <param name="sender">Sender of this event, unused.</param>508        /// <param name="eventArgs">Arguments describing this event.</param>509        private void HandleInformationalMessageReceived(object sender,510            RemoteDataEventArgs<InformationalMessage> eventArgs)511        {512            using (s_tracer.TraceEventHandlers())513            {514                InformationalMessage infoMessage = eventArgs.Data;515 516                switch (infoMessage.DataType)517                {518                    case RemotingDataType.PowerShellDebug:519                        {520                            informationalBuffers.AddDebug((DebugRecord)infoMessage.Message);521                        }522 523                        break;524 525                    case RemotingDataType.PowerShellVerbose:526                        {527                            informationalBuffers.AddVerbose((VerboseRecord)infoMessage.Message);528                        }529 530                        break;531 532                    case RemotingDataType.PowerShellWarning:533                        {534                            informationalBuffers.AddWarning((WarningRecord)infoMessage.Message);535                        }536 537                        break;538 539                    case RemotingDataType.PowerShellProgress:540                        {541                            ProgressRecord progress = (ProgressRecord)LanguagePrimitives.ConvertTo(infoMessage.Message,542                                typeof(ProgressRecord), System.Globalization.CultureInfo.InvariantCulture);543                            informationalBuffers.AddProgress(progress);544                        }545 546                        break;547 548                    case RemotingDataType.PowerShellInformationStream:549                        {550                            informationalBuffers.AddInformation((InformationRecord)infoMessage.Message);551                        }552 553                        break;554                }555            }556        }557 558        /// <summary>559        /// </summary>560        /// <param name="sender"></param>561        /// <param name="eventArgs"></param>562        private void HandleHostCallReceived(object sender, RemoteDataEventArgs<RemoteHostCall> eventArgs)563        {564            using (s_tracer.TraceEventHandlers())565            {566                Collection<RemoteHostCall> prerequisiteCalls =567                    eventArgs.Data.PerformSecurityChecksOnHostMessage(computerName);568 569                if (HostCallReceived != null)570                {571                    // raise events for all prerequisite calls572                    if (prerequisiteCalls.Count > 0)573                    {574                        foreach (RemoteHostCall hostcall in prerequisiteCalls)575                        {576                            RemoteDataEventArgs<RemoteHostCall> args =577                                new RemoteDataEventArgs<RemoteHostCall>(hostcall);578 579                            HostCallReceived.SafeInvoke(this, args);580                        }581                    }582 583                    HostCallReceived.SafeInvoke(this, eventArgs);584                }585                else586                {587                    // execute any prerequisite calls before588                    // executing this host call589                    if (prerequisiteCalls.Count > 0)590                    {591                        foreach (RemoteHostCall hostcall in prerequisiteCalls)592                        {593                            ExecuteHostCall(hostcall);594                        }595                    }596 597                    ExecuteHostCall(eventArgs.Data);598                }599            }600        }601 602        /// <summary>603        /// Handler for ConnectCompleted and ReconnectCompleted events from the604        /// PSRP layer.605        /// </summary>606        /// <param name="sender">Sender of this event, unused.</param>607        /// <param name="e">Event arguments.</param>608        private void HandleConnectCompleted(object sender, RemoteDataEventArgs<Exception> e)609        {610            // After initial connect/reconnect set state to "Running".  Later events611            // will update state to appropriate command execution state.612            SetStateInfo(new PSInvocationStateInfo(PSInvocationState.Running, null));613        }614 615        /// <summary>616        /// This is need for the state change events that resulted in closing the underlying617        /// datastructure handler. We cannot send the state back to the upper layers until618        /// close is completed from the datastructure/transport layer. We have to send619        /// the terminal state only when we know that underlying datastructure/transport620        /// is closed.621        /// </summary>622        /// <param name="sender"></param>623        /// <param name="args"></param>624        private void HandleCloseCompleted(object sender, EventArgs args)625        {626            // if state is completed or failed or stopped,627            // then the collections need to be closed as628            // well, else the enumerator will block629            UnblockCollections();630 631            // close the transport manager when CreateCloseAckPacket is received632            // otherwise may have race conditions in Server.OutOfProcessMediator633            dataStructureHandler.RaiseRemoveAssociationEvent();634 635            if (_stateInfoQueue.Count == 0)636            {637                // If shell state is not finished on client side and queue is empty638                // then set state to stopped unless the current state is Disconnected639                // in which case transition state to failed.640                if (!IsFinished(shell.InvocationStateInfo.State))641                {642                    // If RemoteSessionStateEventArgs are provided then use them to set the643                    // session close reason when setting finished state.644                    RemoteSessionStateEventArgs sessionEventArgs = args as RemoteSessionStateEventArgs;645                    Exception closeReason = sessionEventArgs?.SessionStateInfo.Reason;646                    PSInvocationState finishedState = (shell.InvocationStateInfo.State == PSInvocationState.Disconnected) ?647                        PSInvocationState.Failed : PSInvocationState.Stopped;648 649                    SetStateInfo(new PSInvocationStateInfo(finishedState, closeReason));650                }651            }652            else653            {654                // Apply queued state changes.655                while (_stateInfoQueue.Count > 0)656                {657                    PSInvocationStateInfo stateInfo = _stateInfoQueue.Dequeue();658                    SetStateInfo(stateInfo);659                }660            }661        }662 663        private static bool IsFinished(PSInvocationState state)664        {665            return (state == PSInvocationState.Completed ||666                    state == PSInvocationState.Failed ||667                    state == PSInvocationState.Stopped);668        }669 670        /// <summary>671        /// Execute the specified host call.672        /// </summary>673        /// <param name="hostcall">Host call to execute.</param>674        private void ExecuteHostCall(RemoteHostCall hostcall)675        {676            if (hostcall.IsVoidMethod)677            {678                if (hostcall.IsSetShouldExitOrPopRunspace)679                {680                    this.shell.ClearRemotePowerShell();681                }682 683                hostcall.ExecuteVoidMethod(hostToUse);684            }685            else686            {687                RemoteHostResponse remoteHostResponse = hostcall.ExecuteNonVoidMethod(hostToUse);688                dataStructureHandler.SendHostResponseToServer(remoteHostResponse);689            }690        }691 692        /// <summary>693        /// </summary>694        /// <param name="sender"></param>695        /// <param name="eventArgs"></param>696        private void HandleCloseNotificationFromRunspacePool(object sender,697            RemoteDataEventArgs<Exception> eventArgs)698        {699            // RunspacePool is closed...so going to set the state of PowerShell700            // to stopped here.701 702            // if state is completed or failed or stopped,703            // then the collections need to be closed as704            // well, else the enumerator will block705            UnblockCollections();706 707            // Since this is a terminal state..close the transport manager.708            dataStructureHandler.RaiseRemoveAssociationEvent();709 710            // RunspacePool is closed...so going to set the state of PowerShell711            // to stopped here.712            SetStateInfo(new PSInvocationStateInfo(PSInvocationState.Stopped,713                eventArgs.Data));714 715            // Not calling dataStructureHandler.CloseConnection() as this must716            // have already been called by RunspacePool.Close()717        }718 719        /// <summary>720        /// Handles notification from RunspacePool indicating721        /// that the pool is broken. This sets the state of722        /// all the powershell objects associated with the723        /// runspace pool to Failed.724        /// </summary>725        /// <param name="sender">Sender of this information, unused.</param>726        /// <param name="eventArgs">arguments describing this event727        /// contains information on the reason associated with the728        /// runspace pool entering a Broken state</param>729        private void HandleBrokenNotificationFromRunspacePool(object sender,730            RemoteDataEventArgs<Exception> eventArgs)731        {732            // RunspacePool is closed...so going to set the state of PowerShell733            // to stopped here.734 735            // if state is completed or failed or stopped,736            // then the collections need to be closed as737            // well, else the enumerator will block738            UnblockCollections();739 740            // Since this is a terminal state..close the transport manager.741            dataStructureHandler.RaiseRemoveAssociationEvent();742            if (stopCalled)743            {744                // Reset stop called flag.745                stopCalled = false;746 747                // if a Stop method has been called, then powershell748                // would have already raised a Stopping event, after749                // which only a Stopped should be raised750                SetStateInfo(new PSInvocationStateInfo(PSInvocationState.Stopped,751                    eventArgs.Data));752            }753            else754            {755                SetStateInfo(new PSInvocationStateInfo(PSInvocationState.Failed,756                eventArgs.Data));757            }758 759            // Not calling dataStructureHandler.CloseConnection() as this must760            // have already been called by RunspacePool.Close()761        }762 763        /// <summary>764        /// Handles a robust connection layer notification from the transport765        /// manager.766        /// </summary>767        /// <param name="sender"></param>768        /// <param name="e"></param>769        private void HandleRobustConnectionNotification(770            object sender,771            ConnectionStatusEventArgs e)772        {773            // Create event arguments and warnings/errors for this robust connection notification.774            PSConnectionRetryStatusEventArgs connectionRetryStatusArgs = null;775            WarningRecord warningRecord = null;776            ErrorRecord errorRecord = null;777            int maxRetryConnectionTimeMSecs = this.runspacePool.MaxRetryConnectionTime;778            int maxRetryConnectionTimeMinutes = maxRetryConnectionTimeMSecs / 60000;779            switch (e.Notification)780            {781                case ConnectionStatus.NetworkFailureDetected:782                    warningRecord = new WarningRecord(783                        PSConnectionRetryStatusEventArgs.FQIDNetworkFailureDetected,784                        StringUtil.Format(RemotingErrorIdStrings.RCNetworkFailureDetected,785                        this.computerName, maxRetryConnectionTimeMinutes));786 787                    connectionRetryStatusArgs =788                        new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.NetworkFailureDetected,789                            this.computerName, maxRetryConnectionTimeMSecs, warningRecord);790                    break;791 792                case ConnectionStatus.ConnectionRetryAttempt:793                    warningRecord = new WarningRecord(794                        PSConnectionRetryStatusEventArgs.FQIDConnectionRetryAttempt,795                        StringUtil.Format(RemotingErrorIdStrings.RCConnectionRetryAttempt, this.computerName));796 797                    connectionRetryStatusArgs =798                        new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.ConnectionRetryAttempt,799                            this.computerName, maxRetryConnectionTimeMSecs, warningRecord);800                    break;801 802                case ConnectionStatus.ConnectionRetrySucceeded:803                    warningRecord = new WarningRecord(804                        PSConnectionRetryStatusEventArgs.FQIDConnectionRetrySucceeded,805                        StringUtil.Format(RemotingErrorIdStrings.RCReconnectSucceeded, this.computerName));806 807                    connectionRetryStatusArgs =808                        new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.ConnectionRetrySucceeded,809                            this.computerName, maxRetryConnectionTimeMinutes, warningRecord);810                    break;811 812                case ConnectionStatus.AutoDisconnectStarting:813                    {814                        warningRecord = new WarningRecord(815                            PSConnectionRetryStatusEventArgs.FQIDAutoDisconnectStarting,816                            StringUtil.Format(RemotingErrorIdStrings.RCAutoDisconnectingWarning, this.computerName));817 818                        connectionRetryStatusArgs =819                            new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.AutoDisconnectStarting,820                                this.computerName, maxRetryConnectionTimeMinutes, warningRecord);821                    }822 823                    break;824 825                case ConnectionStatus.AutoDisconnectSucceeded:826                    warningRecord = new WarningRecord(827                        PSConnectionRetryStatusEventArgs.FQIDAutoDisconnectSucceeded,828                        StringUtil.Format(RemotingErrorIdStrings.RCAutoDisconnected, this.computerName));829 830                    connectionRetryStatusArgs =831                        new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.AutoDisconnectSucceeded,832                            this.computerName, maxRetryConnectionTimeMinutes, warningRecord);833                    break;834 835                case ConnectionStatus.InternalErrorAbort:836                    {837                        string msg = StringUtil.Format(RemotingErrorIdStrings.RCInternalError, this.computerName);838                        RuntimeException reason = new RuntimeException(msg);839                        errorRecord = new ErrorRecord(reason,840                            PSConnectionRetryStatusEventArgs.FQIDNetworkOrDisconnectFailed,841                            ErrorCategory.InvalidOperation, this);842 843                        connectionRetryStatusArgs =844                            new PSConnectionRetryStatusEventArgs(PSConnectionRetryStatus.InternalErrorAbort,845                                this.computerName, maxRetryConnectionTimeMinutes, errorRecord);846                    }847 848                    break;849            }850 851            if (connectionRetryStatusArgs == null)852            {853                return;854            }855 856            // Update connection status.857            _connectionRetryStatus = connectionRetryStatusArgs.Notification;858 859            if (warningRecord != null)860            {861                RemotingWarningRecord remotingWarningRecord = new RemotingWarningRecord(862                    warningRecord,863                    new OriginInfo(this.computerName, this.InstanceId));864 865                // Add warning record to information channel.866                HandleInformationalMessageReceived(this,867                    new RemoteDataEventArgs<InformationalMessage>(868                        new InformationalMessage(remotingWarningRecord, RemotingDataType.PowerShellWarning)));869 870                // Write warning to host.871                RemoteHostCall writeWarning = new RemoteHostCall(872                    -100,873                    RemoteHostMethodId.WriteWarningLine,874                    new object[] { warningRecord.Message });875 876                try877                {878                    HandleHostCallReceived(this,879                        new RemoteDataEventArgs<RemoteHostCall>(writeWarning));880                }881                catch (PSNotImplementedException)882                { }883            }884 885            if (errorRecord != null)886            {887                RemotingErrorRecord remotingErrorRecord = new RemotingErrorRecord(888                    errorRecord,889                    new OriginInfo(this.computerName, this.InstanceId));890 891                // Add error record to error channel, will also be written to host.892                HandleErrorReceived(this,893                    new RemoteDataEventArgs<ErrorRecord>(remotingErrorRecord));894            }895 896            // Raise event.897            RCConnectionNotification.SafeInvoke(this, connectionRetryStatusArgs);898        }899 900        #endregion Private Methods901 902        #region Private Fields903 904        private ObjectStreamBase inputstream;905        private ObjectStreamBase errorstream;906        private PSInformationalBuffers informationalBuffers;907        private readonly PowerShell shell;908        private readonly Guid clientRunspacePoolId;909        private bool noInput;910        private PSInvocationSettings settings;911        private ObjectStreamBase outputstream;912        private readonly string computerName;913        private ClientPowerShellDataStructureHandler dataStructureHandler;914        private bool stopCalled = false;915        private PSHost hostToUse;916        private readonly RemoteRunspacePoolInternal runspacePool;917 918        private const string WRITE_DEBUG_LINE = "WriteDebugLine";919        private const string WRITE_VERBOSE_LINE = "WriteVerboseLine";920        private const string WRITE_WARNING_LINE = "WriteWarningLine";921        private const string WRITE_PROGRESS = "WriteProgress";922 923        private bool initialized = false;924        /// <summary>925        /// This queue is for the state change events that resulted in closing the underlying926        /// datastructure handler. We cannot send the state back to the upper layers until927        /// close is completed from the datastructure/transport layer.928        /// </summary>929        private readonly Queue<PSInvocationStateInfo> _stateInfoQueue = new Queue<PSInvocationStateInfo>();930 931        private PSConnectionRetryStatus _connectionRetryStatus = PSConnectionRetryStatus.None;932 933        #endregion Private Fields934 935        #region IDisposable936 937        /// <summary>938        /// Release all resources.939        /// </summary>940        public void Dispose()941        {942            // inputstream.Dispose();943            // outputstream.Dispose();944            // errorstream.Dispose();945        }946 947        #endregion IDisposable948    }949 950    #region PSConnectionRetryStatusEventArgs951 952    /// <summary>953    /// Robust Connection notifications.954    /// </summary>955    internal enum PSConnectionRetryStatus956    {957        None = 0,958        NetworkFailureDetected = 1,959        ConnectionRetryAttempt = 2,960        ConnectionRetrySucceeded = 3,961        AutoDisconnectStarting = 4,962        AutoDisconnectSucceeded = 5,963        InternalErrorAbort = 6964    }965 966    /// <summary>967    /// PSConnectionRetryStatusEventArgs.968    /// </summary>969    internal sealed class PSConnectionRetryStatusEventArgs : EventArgs970    {971        internal const string FQIDNetworkFailureDetected = "PowerShellNetworkFailureDetected";972        internal const string FQIDConnectionRetryAttempt = "PowerShellConnectionRetryAttempt";973        internal const string FQIDConnectionRetrySucceeded = "PowerShellConnectionRetrySucceeded";974        internal const string FQIDAutoDisconnectStarting = "PowerShellNetworkFailedStartDisconnect";975        internal const string FQIDAutoDisconnectSucceeded = "PowerShellAutoDisconnectSucceeded";976        internal const string FQIDNetworkOrDisconnectFailed = "PowerShellNetworkOrDisconnectFailed";977 978        internal PSConnectionRetryStatusEventArgs(979            PSConnectionRetryStatus notification,980            string computerName,981            int maxRetryConnectionTime,982            object infoRecord)983        {984            Notification = notification;985            ComputerName = computerName;986            MaxRetryConnectionTime = maxRetryConnectionTime;987            InformationRecord = infoRecord;988        }989 990        internal PSConnectionRetryStatus Notification { get; }991 992        internal string ComputerName { get; }993 994        internal int MaxRetryConnectionTime { get; }995 996        internal object InformationRecord { get; }997    }998 999    #endregion1000}1001