Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ServerRemoteHost.cs484 linesDownload Raw Back to server
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Globalization;5using System.Management.Automation.Host;6using System.Management.Automation.Remoting.Server;7using System.Management.Automation.Runspaces;8 9using Dbg = System.Management.Automation.Diagnostics;10 11namespace System.Management.Automation.Remoting12{13    /// <summary>14    /// The ServerRemoteHost class.15    /// </summary>16    internal class ServerRemoteHost : PSHost, IHostSupportsInteractiveSession17    {18        #region Private Members19 20        /// <summary>21        /// Remote host user interface.22        /// </summary>23        private readonly ServerRemoteHostUserInterface _remoteHostUserInterface;24 25        /// <summary>26        /// Server method executor.27        /// </summary>28        private readonly ServerMethodExecutor _serverMethodExecutor;29 30        /// <summary>31        /// Client runspace pool id.32        /// </summary>33        private readonly Guid _clientRunspacePoolId;34 35        /// <summary>36        /// Client power shell id.37        /// </summary>38        private readonly Guid _clientPowerShellId;39 40        /// <summary>41        /// Transport manager.42        /// </summary>43        protected AbstractServerTransportManager _transportManager;44 45        /// <summary>46        /// ServerDriverRemoteHost.47        /// </summary>48        private readonly ServerDriverRemoteHost _serverDriverRemoteHost;49 50        #endregion51 52        #region Constructor53 54        /// <summary>55        /// Constructor for ServerRemoteHost.56        /// </summary>57        internal ServerRemoteHost(58            Guid clientRunspacePoolId,59            Guid clientPowerShellId,60            HostInfo hostInfo,61            AbstractServerTransportManager transportManager,62            Runspace runspace,63            ServerDriverRemoteHost serverDriverRemoteHost)64        {65            _clientRunspacePoolId = clientRunspacePoolId;66            _clientPowerShellId = clientPowerShellId;67            Dbg.Assert(hostInfo != null, "Expected hostInfo != null");68            Dbg.Assert(transportManager != null, "Expected transportManager != null");69 70            // Set host-info and the transport-manager.71            HostInfo = hostInfo;72            _transportManager = transportManager;73            _serverDriverRemoteHost = serverDriverRemoteHost;74 75            // Create the executor for the host methods.76            _serverMethodExecutor = new ServerMethodExecutor(77                clientRunspacePoolId, clientPowerShellId, _transportManager);78 79            // Use HostInfo to create host-UI as null or non-null based on the client's host-UI.80            _remoteHostUserInterface = hostInfo.IsHostUINull ? null : new ServerRemoteHostUserInterface(this);81 82            Runspace = runspace;83        }84 85        #endregion86 87        #region Properties88 89        /// <summary>90        /// Server method executor.91        /// </summary>92        internal ServerMethodExecutor ServerMethodExecutor93        {94            get { return _serverMethodExecutor; }95        }96 97        /// <summary>98        /// The user interface.99        /// </summary>100        public override PSHostUserInterface UI101        {102            get { return _remoteHostUserInterface; }103        }104 105        /// <summary>106        /// Name.107        /// </summary>108        public override string Name109        {110            get { return "ServerRemoteHost"; }111        }112 113        /// <summary>114        /// Version.115        /// </summary>116        public override Version Version117        {118            get { return RemotingConstants.HostVersion; }119        }120 121        /// <summary>122        /// Instance id.123        /// </summary>124        public override Guid InstanceId { get; } = Guid.NewGuid();125 126        /// <summary>127        /// Is runspace pushed.128        /// </summary>129        public virtual bool IsRunspacePushed130        {131            get132            {133                if (_serverDriverRemoteHost != null)134                {135                    return _serverDriverRemoteHost.IsRunspacePushed;136                }137                else138                {139                    throw RemoteHostExceptions.NewNotImplementedException(RemoteHostMethodId.GetIsRunspacePushed);140                }141            }142        }143 144        /// <summary>145        /// Runspace.146        /// </summary>147        public Runspace Runspace { get; internal set; }148 149        /// <summary>150        /// Host info.151        /// </summary>152        internal HostInfo HostInfo { get; }153 154        #endregion155 156        #region Method Overrides157 158        /// <summary>159        /// Set should exit.160        /// </summary>161        public override void SetShouldExit(int exitCode)162        {163            _serverMethodExecutor.ExecuteVoidMethod(RemoteHostMethodId.SetShouldExit, new object[] { exitCode });164        }165 166        /// <summary>167        /// Enter nested prompt.168        /// </summary>169        public override void EnterNestedPrompt()170        {171            throw RemoteHostExceptions.NewNotImplementedException(RemoteHostMethodId.EnterNestedPrompt);172        }173 174        /// <summary>175        /// Exit nested prompt.176        /// </summary>177        public override void ExitNestedPrompt()178        {179            throw RemoteHostExceptions.NewNotImplementedException(RemoteHostMethodId.ExitNestedPrompt);180        }181 182        /// <summary>183        /// Notify begin application.184        /// </summary>185        public override void NotifyBeginApplication()186        {187            // This is called when a native application is executed on the server. It gives the188            // host an opportunity to save state that might be altered by the native application.189            // This call should not be sent to the client because the native application running190            // on the server cannot affect the state of the machine on the client.191        }192 193        /// <summary>194        /// Notify end application.195        /// </summary>196        public override void NotifyEndApplication()197        {198            // See note in NotifyBeginApplication.199        }200 201        /// <summary>202        /// Current culture.203        /// </summary>204        public override CultureInfo CurrentCulture205        {206            get207            {208                // Return the thread's current culture and rely on WinRM to set this209                // correctly based on the client's culture.210                return CultureInfo.CurrentCulture;211            }212        }213 214        /// <summary>215        /// Current ui culture.216        /// </summary>217        public override CultureInfo CurrentUICulture218        {219            get220            {221                // Return the thread's current UI culture and rely on WinRM to set222                // this correctly based on the client's UI culture.223                return CultureInfo.CurrentUICulture;224            }225        }226 227        #endregion228 229        #region Methods230 231        /// <summary>232        /// Push runspace.233        /// </summary>234        public virtual void PushRunspace(Runspace runspace)235        {236            if (_serverDriverRemoteHost != null)237            {238                _serverDriverRemoteHost.PushRunspace(runspace);239            }240            else241            {242                throw RemoteHostExceptions.NewNotImplementedException(RemoteHostMethodId.PushRunspace);243            }244        }245 246        /// <summary>247        /// Pop runspace.248        /// </summary>249        public virtual void PopRunspace()250        {251            if ((_serverDriverRemoteHost != null) && (_serverDriverRemoteHost.IsRunspacePushed))252            {253                if (_serverDriverRemoteHost.PropagatePop)254                {255                    // Forward the PopRunspace command to client and keep *this* pushed runspace as256                    // the configured JEA restricted session.257                    _serverMethodExecutor.ExecuteVoidMethod(RemoteHostMethodId.PopRunspace);258                }259                else260                {261                    _serverDriverRemoteHost.PopRunspace();262                }263            }264            else265            {266                _serverMethodExecutor.ExecuteVoidMethod(RemoteHostMethodId.PopRunspace);267            }268        }269 270        #endregion271    }272 273    /// <summary>274    /// The remote host class for the ServerRunspacePoolDriver.275    /// </summary>276    internal class ServerDriverRemoteHost : ServerRemoteHost277    {278        #region Private Members279 280        private RemoteRunspace _pushedRunspace;281        private ServerRemoteDebugger _debugger;282        private bool _hostSupportsPSEdit;283 284        #endregion285 286        #region Constructor287 288        internal ServerDriverRemoteHost(289            Guid clientRunspacePoolId,290            Guid clientPowerShellId,291            HostInfo hostInfo,292            AbstractServerSessionTransportManager transportManager,293            ServerRemoteDebugger debugger)294            : base(clientRunspacePoolId, clientPowerShellId, hostInfo, transportManager, null, null)295        {296            _debugger = debugger;297        }298 299        #endregion300 301        #region Overrides302 303        /// <summary>304        /// True if runspace is pushed.305        /// </summary>306        public override bool IsRunspacePushed307        {308            get309            {310                return (_pushedRunspace != null);311            }312        }313 314        /// <summary>315        /// Push runspace to use for remote command execution.316        /// </summary>317        /// <param name="runspace">RemoteRunspace.</param>318        public override void PushRunspace(Runspace runspace)319        {320            if (_debugger == null)321            {322                throw new PSInvalidOperationException(RemotingErrorIdStrings.ServerDriverRemoteHostNoDebuggerToPush);323            }324 325            if (_pushedRunspace != null)326            {327                throw new PSInvalidOperationException(RemotingErrorIdStrings.ServerDriverRemoteHostAlreadyPushed);328            }329 330            if (runspace is not RemoteRunspace remoteRunspace)331            {332                throw new PSInvalidOperationException(RemotingErrorIdStrings.ServerDriverRemoteHostNotRemoteRunspace);333            }334 335            // PSEdit support.  Existence of RemoteSessionOpenFileEvent event indicates host supports PSEdit336            _hostSupportsPSEdit = false;337            PSEventManager localEventManager = Runspace?.Events;338            _hostSupportsPSEdit = localEventManager != null && localEventManager.GetEventSubscribers(HostUtilities.RemoteSessionOpenFileEvent).GetEnumerator().MoveNext();339            if (_hostSupportsPSEdit)340            {341                AddPSEditForRunspace(remoteRunspace);342            }343 344            _debugger.PushDebugger(runspace.Debugger);345            _pushedRunspace = remoteRunspace;346        }347 348        /// <summary>349        /// Pop runspace.350        /// </summary>351        public override void PopRunspace()352        {353            if (_pushedRunspace != null)354            {355                _debugger?.PopDebugger();356 357                if (_hostSupportsPSEdit)358                {359                    RemovePSEditFromRunspace(_pushedRunspace);360                }361 362                if (_pushedRunspace.ShouldCloseOnPop)363                {364                    _pushedRunspace.Close();365                }366 367                _pushedRunspace = null;368            }369        }370 371        #endregion372 373        #region Properties374 375        /// <summary>376        /// Server Debugger.377        /// </summary>378        internal Debugger ServerDebugger379        {380            get { return _debugger; }381 382            set { _debugger = value as ServerRemoteDebugger; }383        }384 385        /// <summary>386        /// Pushed runspace or null.387        /// </summary>388        internal Runspace PushedRunspace389        {390            get { return _pushedRunspace; }391        }392 393        /// <summary>394        /// When true will propagate pop call to client after popping runspace from this395        /// host.  Used for OutOfProc remote sessions in a restricted (pushed) remote runspace,396        /// where a pop (exit session) should occur.397        /// </summary>398        internal bool PropagatePop399        {400            get;401            set;402        }403 404        #endregion405 406        #region PSEdit Support for ISE Host407 408        private void AddPSEditForRunspace(RemoteRunspace remoteRunspace)409        {410            if (remoteRunspace.Events == null)411            {412                return;413            }414 415            // Add event handler.416            remoteRunspace.Events.ReceivedEvents.PSEventReceived += HandleRemoteSessionForwardedEvent;417 418            // Add script function.419            using (PowerShell powershell = PowerShell.Create())420            {421                powershell.Runspace = remoteRunspace;422                powershell.AddScript(HostUtilities.CreatePSEditFunction).AddParameter("PSEditFunction", HostUtilities.PSEditFunction);423                try424                {425                    powershell.Invoke();426                }427                catch (RemoteException) { }428            }429        }430 431        private void RemovePSEditFromRunspace(RemoteRunspace remoteRunspace)432        {433            if (remoteRunspace.Events == null)434            {435                return;436            }437 438            // It is possible for the popped runspace to be in a bad state after an error.439            if ((remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened) || (remoteRunspace.RunspaceAvailability != RunspaceAvailability.Available))440            {441                return;442            }443 444            // Remove event handler.445            remoteRunspace.Events.ReceivedEvents.PSEventReceived -= HandleRemoteSessionForwardedEvent;446 447            // Remove script function.448            using (PowerShell powershell = PowerShell.Create())449            {450                powershell.Runspace = remoteRunspace;451                powershell.AddScript(HostUtilities.RemovePSEditFunction);452                try453                {454                    powershell.Invoke();455                }456                catch (RemoteException) { }457            }458        }459 460        private void HandleRemoteSessionForwardedEvent(object sender, PSEventArgs args)461        {462            if ((Runspace == null) || (Runspace.Events == null))463            {464                return;465            }466 467            // Forward events from nested pushed session to parent session.468            try469            {470                Runspace.Events.GenerateEvent(471                    sourceIdentifier: args.SourceIdentifier,472                    sender: null,473                    args: args.SourceArgs,474                    extraData: null);475            }476            catch (Exception)477            {478            }479        }480 481        #endregion482    }483}484