Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ClientMethodExecutor.cs244 linesDownload Raw Back to client
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Management.Automation.Host;5using System.Management.Automation.Internal;6using System.Management.Automation.Remoting.Client;7using System.Management.Automation.Runspaces.Internal;8 9using Dbg = System.Management.Automation.Diagnostics;10 11namespace System.Management.Automation.Remoting12{13    /// <summary>14    /// Executes methods on the client.15    /// </summary>16    internal sealed class ClientMethodExecutor17    {18        /// <summary>19        /// Transport manager.20        /// </summary>21        private readonly BaseClientTransportManager _transportManager;22 23        /// <summary>24        /// Client host.25        /// </summary>26        private readonly PSHost _clientHost;27 28        /// <summary>29        /// Client runspace pool id.30        /// </summary>31        private readonly Guid _clientRunspacePoolId;32 33        /// <summary>34        /// Client power shell id.35        /// </summary>36        private readonly Guid _clientPowerShellId;37 38        /// <summary>39        /// Remote host call.40        /// </summary>41        private readonly RemoteHostCall _remoteHostCall;42 43        /// <summary>44        /// Remote host call.45        /// </summary>46        internal RemoteHostCall RemoteHostCall47        {48            get49            {50                return _remoteHostCall;51            }52        }53 54        /// <summary>55        /// Constructor for ClientMethodExecutor.56        /// </summary>57        private ClientMethodExecutor(BaseClientTransportManager transportManager, PSHost clientHost, Guid clientRunspacePoolId, Guid clientPowerShellId, RemoteHostCall remoteHostCall)58        {59            Dbg.Assert(transportManager != null, "Expected transportManager != null");60            Dbg.Assert(remoteHostCall != null, "Expected remoteHostCall != null");61            _transportManager = transportManager;62            _remoteHostCall = remoteHostCall;63            _clientHost = clientHost;64            _clientRunspacePoolId = clientRunspacePoolId;65            _clientPowerShellId = clientPowerShellId;66        }67 68        /// <summary>69        /// Create a new ClientMethodExecutor object and then dispatch it.70        /// </summary>71        internal static void Dispatch(72            BaseClientTransportManager transportManager,73            PSHost clientHost,74            PSDataCollectionStream<ErrorRecord> errorStream,75            ObjectStream methodExecutorStream,76            bool isMethodExecutorStreamEnabled,77            RemoteRunspacePoolInternal runspacePool,78            Guid clientPowerShellId,79            RemoteHostCall remoteHostCall)80        {81            ClientMethodExecutor methodExecutor =82                new ClientMethodExecutor(transportManager, clientHost, runspacePool.InstanceId,83                    clientPowerShellId, remoteHostCall);84 85            // If the powershell id is not specified, this message is for the runspace pool, execute86            // it immediately and return87            if (clientPowerShellId == Guid.Empty)88            {89                methodExecutor.Execute(errorStream);90                return;91            }92 93            // Check client host to see if SetShouldExit should be allowed94            bool hostAllowSetShouldExit = false;95            if (clientHost != null)96            {97                PSObject hostPrivateData = clientHost.PrivateData as PSObject;98                if (hostPrivateData != null)99                {100                    PSNoteProperty allowSetShouldExit = hostPrivateData.Properties["AllowSetShouldExitFromRemote"] as PSNoteProperty;101                    hostAllowSetShouldExit = allowSetShouldExit != null && allowSetShouldExit.Value is bool && (bool)allowSetShouldExit.Value;102                }103            }104 105            // Should we kill remote runspace? Check if "SetShouldExit" and if we are in the106            // cmdlet case. In the API case (when we are invoked from an API not a cmdlet) we107            // should not interpret "SetShouldExit" but should pass it on to the host. The108            // variable IsMethodExecutorStreamEnabled is only true in the cmdlet case. In the109            // API case it is false.110 111            if (remoteHostCall.IsSetShouldExit && isMethodExecutorStreamEnabled && !hostAllowSetShouldExit)112            {113                runspacePool.Close();114                return;115            }116 117            // Cmdlet case: queue up the executor in the pipeline stream.118            if (isMethodExecutorStreamEnabled)119            {120                Dbg.Assert(methodExecutorStream != null, "method executor stream can't be null when enabled");121                methodExecutorStream.Write(methodExecutor);122            }123 124            // API case: execute it immediately.125            else126            {127                methodExecutor.Execute(errorStream);128            }129        }130 131        /// <summary>132        /// Is runspace pushed.133        /// </summary>134        private static bool IsRunspacePushed(PSHost host)135        {136            if (host is not IHostSupportsInteractiveSession host2)137            {138                return false;139            }140 141            // IsRunspacePushed can throw (not implemented exception)142            try143            {144                return host2.IsRunspacePushed;145            }146            catch (PSNotImplementedException) { }147 148            return false;149        }150 151        /// <summary>152        /// Execute.153        /// </summary>154        internal void Execute(PSDataCollectionStream<ErrorRecord> errorStream)155        {156            Action<ErrorRecord> writeErrorAction = null;157 158            // If error-stream is null or we are in pushed-runspace - then write error directly to console.159            if (errorStream == null || IsRunspacePushed(_clientHost))160            {161                writeErrorAction = (ErrorRecord errorRecord) =>162                {163                    try164                    {165                        _clientHost.UI?.WriteErrorLine(errorRecord.ToString());166                    }167                    catch (Exception)168                    {169                        // Catch-all OK, 3rd party callout.170                    }171                };172            }173 174            // Otherwise write it to error-stream.175            else176            {177                writeErrorAction = (ErrorRecord errorRecord) => errorStream.Write(errorRecord);178            }179 180            this.Execute(writeErrorAction);181        }182 183        /// <summary>184        /// Execute.185        /// </summary>186        internal void Execute(Cmdlet cmdlet)187        {188            this.Execute(cmdlet.WriteError);189        }190 191        /// <summary>192        /// Execute.193        /// </summary>194        internal void Execute(Action<ErrorRecord> writeErrorAction)195        {196            if (_remoteHostCall.IsVoidMethod)197            {198                ExecuteVoid(writeErrorAction);199            }200            else201            {202                RemotingDataType remotingDataType =203                    _clientPowerShellId == Guid.Empty ? RemotingDataType.RemoteRunspaceHostResponseData : RemotingDataType.RemotePowerShellHostResponseData;204 205                RemoteHostResponse remoteHostResponse = _remoteHostCall.ExecuteNonVoidMethod(_clientHost);206                RemoteDataObject<PSObject> dataToBeSent = RemoteDataObject<PSObject>.CreateFrom(207                    RemotingDestination.Server, remotingDataType, _clientRunspacePoolId,208                    _clientPowerShellId, remoteHostResponse.Encode());209 210                _transportManager.DataToBeSentCollection.Add<PSObject>(dataToBeSent, DataPriorityType.PromptResponse);211            }212        }213 214        /// <summary>215        /// Execute void.216        /// </summary>217        internal void ExecuteVoid(Action<ErrorRecord> writeErrorAction)218        {219            try220            {221                _remoteHostCall.ExecuteVoidMethod(_clientHost);222            }223            catch (Exception exception)224            {225                // Catch-all OK, 3rd party callout.226 227                // Extract inner exception.228                if (exception.InnerException != null)229                {230                    exception = exception.InnerException;231                }232 233                // Create an error record and write it to the stream.234                ErrorRecord errorRecord = new ErrorRecord(235                    exception,236                    nameof(PSRemotingErrorId.RemoteHostCallFailed),237                    ErrorCategory.InvalidArgument,238                    _remoteHostCall.MethodName);239                writeErrorAction(errorRecord);240            }241        }242    }243}244