Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ReceivePSSession.cs1343 linesDownload Raw Back to commands
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics.CodeAnalysis;8using System.Management.Automation;9using System.Management.Automation.Internal;10using System.Management.Automation.Remoting;11using System.Management.Automation.Remoting.Client;12using System.Management.Automation.Runspaces;13using System.Threading;14 15using Dbg = System.Management.Automation.Diagnostics;16 17namespace Microsoft.PowerShell.Commands18{19    /// <summary>20    /// This cmdlet connects a running command associated with a PS session and then21    /// directs the command output either:22    /// a) To Host.  This is the synchronous mode of the cmdlet which won't return23    ///    until the running command completes and all output data is received on24    ///    the client.25    /// b) To a job object.  This is the asynchronous mode of the cmdlet which will26    ///    return immediately providing the job object that is collecting the27    ///    running command output data.28    ///29    /// The running command becomes disconnected when the associated runspace is30    /// disconnected (via the Disconnect-PSSession cmdlet).31    ///32    /// The associated runspace object must be in the Opened state (connected) before33    /// the running command can be connected.  If the associated runspace object is34    /// in the disconnected state, it will first be connected before the running35    /// command is connected.36    ///37    /// The user can specify how command output data is returned by using the public38    /// OutTarget enumeration (Host, Job).39    /// The default actions of this cmdlet is to always direct output to host unless40    /// a job object already exists on the client that is associated with the running41    /// command.  In this case the existing job object is connected to the running42    /// command and returned.43    ///44    /// The cmdlet can be used in the following ways:45    ///46    /// Receive PS session data by session object47    /// > $session = New-PSSession serverName48    /// > $job1 = Invoke-Command $session { [script] } -asjob49    /// > Disconnect-PSSession $session50    /// > Connect-PSSession $session51    /// > Receive-PSSession $session    // command output continues collecting at job object.52    ///53    /// Receive PS session data by session Id54    /// > Receive-PSSession $session.Id55    ///56    /// Receive PS session data by session instance Id57    /// > Receive-PSSession $session.InstanceId58    ///59    /// Receive PS session data by session Name.  Direct output to job60    /// > Receive-PSSession $session.Name61    ///62    /// Receive a running command from a computer.63    /// > $job = Receive-PSSession -ComputerName ServerOne -Name SessionName -OutTarget Job.64    /// </summary>65    [SuppressMessage("Microsoft.PowerShell", "PS1012:CallShouldProcessOnlyIfDeclaringSupport")]66    [Cmdlet(VerbsCommunications.Receive, "PSSession", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low,67        DefaultParameterSetName = ReceivePSSessionCommand.SessionParameterSet, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096800",68        RemotingCapability = RemotingCapability.OwnedByCommand)]69    public class ReceivePSSessionCommand : PSRemotingCmdlet70    {71        #region Parameters72 73        private const string IdParameterSet = "Id";74        private const string InstanceIdParameterSet = "InstanceId";75        private const string NameParameterSet = "SessionName";76        private const string ComputerSessionNameParameterSet = "ComputerSessionName";   // Computer name and session Name.77        private const string ConnectionUriSessionNameParameterSet = "ConnectionUriSessionName";78        private const string ConnectionUriInstanceIdParameterSet = "ConnectionUriInstanceId";79 80        /// <summary>81        /// The PSSession object to receive data from.82        /// </summary>83        [Parameter(Position = 0,84                   Mandatory = true,85                   ValueFromPipelineByPropertyName = true,86                   ValueFromPipeline = true,87                   ParameterSetName = ReceivePSSessionCommand.SessionParameterSet)]88        [ValidateNotNullOrEmpty]89        public PSSession Session { get; set; }90 91        /// <summary>92        /// Session Id of PSSession object to receive data from.93        /// </summary>94        [Parameter(Position = 0,95                   Mandatory = true,96                   ValueFromPipelineByPropertyName = true,97                   ValueFromPipeline = true,98                   ParameterSetName = ReceivePSSessionCommand.IdParameterSet)]99        public int Id { get; set; }100 101        /// <summary>102        /// Computer name to receive session data from.103        /// </summary>104        [Parameter(Position = 0,105                   Mandatory = true,106                   ValueFromPipelineByPropertyName = true,107                   ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]108        [Parameter(Position = 0,109                   Mandatory = true,110                   ValueFromPipelineByPropertyName = true,111                   ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]112        [ValidateNotNullOrEmpty]113        [Alias("Cn")]114        public string ComputerName { get; set; }115 116        /// <summary>117        /// This parameters specifies the appname which identifies the connection118        /// end point on the remote machine. If this parameter is not specified119        /// then the value specified in DEFAULTREMOTEAPPNAME will be used. If that's120        /// not specified as well, then "WSMAN" will be used.121        /// </summary>122        [Parameter(ValueFromPipelineByPropertyName = true,123                   ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]124        [Parameter(ValueFromPipelineByPropertyName = true,125                   ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]126        public string ApplicationName127        {128            get129            {130                return _appName;131            }132 133            set134            {135                _appName = ResolveAppName(value);136            }137        }138 139        private string _appName;140 141        /// <summary>142        /// If this parameter is not specified then the value specified in143        /// the environment variable DEFAULTREMOTESHELLNAME will be used. If144        /// this is not set as well, then Microsoft.PowerShell is used.145        /// </summary>146        [Parameter(ValueFromPipelineByPropertyName = true,147                   ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]148        [Parameter(ValueFromPipelineByPropertyName = true,149                   ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]150        [Parameter(ValueFromPipelineByPropertyName = true,151                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]152        [Parameter(ValueFromPipelineByPropertyName = true,153                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]154        public string ConfigurationName155        {156            get157            {158                return _shell;159            }160 161            set162            {163                _shell = ResolveShell(value);164            }165        }166 167        private string _shell;168 169        /// <summary>170        /// A complete URI(s) specified for the remote computer and shell to171        /// connect to and create a runspace for.172        /// </summary>173        [Parameter(Position = 0, Mandatory = true,174                   ValueFromPipelineByPropertyName = true,175                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]176        [Parameter(Position = 0, Mandatory = true,177                   ValueFromPipelineByPropertyName = true,178                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]179        [ValidateNotNullOrEmpty]180        [Alias("URI", "CU")]181        public Uri ConnectionUri { get; set; }182 183        /// <summary>184        /// The AllowRedirection parameter enables the implicit redirection functionality.185        /// </summary>186        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]187        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]188        public SwitchParameter AllowRedirection189        {190            get { return _allowRedirection; }191 192            set { _allowRedirection = value; }193        }194 195        private bool _allowRedirection = false;196 197        /// <summary>198        /// Instance Id of PSSession object to receive data from.199        /// </summary>200        [Parameter(Position = 0,201                   Mandatory = true,202                   ValueFromPipelineByPropertyName = true,203                   ValueFromPipeline = true,204                   ParameterSetName = ReceivePSSessionCommand.InstanceIdParameterSet)]205        [Parameter(Mandatory = true,206                   ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]207        [Parameter(Mandatory = true,208                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]209        [ValidateNotNullOrEmpty]210        public Guid InstanceId { get; set; }211 212        /// <summary>213        /// Name of PSSession object to receive data from.214        /// </summary>215        [Parameter(Position = 0,216                   Mandatory = true,217                   ValueFromPipelineByPropertyName = true,218                   ValueFromPipeline = true,219                   ParameterSetName = ReceivePSSessionCommand.NameParameterSet)]220        [Parameter(Mandatory = true,221                   ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]222        [Parameter(Mandatory = true,223                   ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]224        [ValidateNotNullOrEmpty]225        public string Name { get; set; }226 227        /// <summary>228        /// Determines how running command output is returned on client.229        /// </summary>230        [Parameter(ParameterSetName = ReceivePSSessionCommand.SessionParameterSet)]231        [Parameter(ParameterSetName = ReceivePSSessionCommand.IdParameterSet)]232        [Parameter(ParameterSetName = ReceivePSSessionCommand.InstanceIdParameterSet)]233        [Parameter(ParameterSetName = ReceivePSSessionCommand.NameParameterSet)]234        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]235        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]236        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]237        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]238        public OutTarget OutTarget { get; set; } = OutTarget.Default;239 240        /// <summary>241        /// Provides job name when job is created for returned data.242        /// </summary>243        [Parameter(ParameterSetName = ReceivePSSessionCommand.SessionParameterSet)]244        [Parameter(ParameterSetName = ReceivePSSessionCommand.IdParameterSet)]245        [Parameter(ParameterSetName = ReceivePSSessionCommand.InstanceIdParameterSet)]246        [Parameter(ParameterSetName = ReceivePSSessionCommand.NameParameterSet)]247        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]248        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]249        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]250        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]251        [ValidateNotNullOrEmpty]252        public string JobName { get; set; } = string.Empty;253 254        /// <summary>255        /// Specifies the credentials of the user to impersonate in the256        /// remote machine. If this parameter is not specified then the257        /// credentials of the current user process will be assumed.258        /// </summary>259        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]260        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]261        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]262        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]263        [Credential]264        public PSCredential Credential265        {266            get267            {268                return _psCredential;269            }270 271            set272            {273                _psCredential = value;274 275                PSRemotingBaseCmdlet.ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);276            }277        }278 279        private PSCredential _psCredential;280 281        /// <summary>282        /// Use basic authentication to authenticate the user.283        /// </summary>284        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]285        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]286        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]287        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]288        public AuthenticationMechanism Authentication289        {290            get291            {292                return _authentication;293            }294 295            set296            {297                _authentication = value;298 299                PSRemotingBaseCmdlet.ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);300            }301        }302 303        private AuthenticationMechanism _authentication;304 305        /// <summary>306        /// Specifies the certificate thumbprint to be used to impersonate the user on the307        /// remote machine.308        /// </summary>309        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]310        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]311        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]312        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]313        public string CertificateThumbprint314        {315            get316            {317                return _thumbprint;318            }319 320            set321            {322                _thumbprint = value;323 324                PSRemotingBaseCmdlet.ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);325            }326        }327 328        private string _thumbprint;329 330        /// <summary>331        /// Port specifies the alternate port to be used in case the332        /// default ports are not used for the transport mechanism333        /// (port 80 for http and port 443 for useSSL)334        /// </summary>335        /// <remarks>336        /// Currently this is being accepted as a parameter. But in future337        /// support will be added to make this a part of a policy setting.338        /// When a policy setting is in place this parameter can be used339        /// to override the policy setting340        /// </remarks>341        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]342        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]343        [ValidateRange((int)1, (int)UInt16.MaxValue)]344        public int Port { get; set; }345 346        /// <summary>347        /// This parameter suggests that the transport scheme to be used for348        /// remote connections is useSSL instead of the default http.Since349        /// there are only two possible transport schemes that are possible350        /// at this point, a SwitchParameter is being used to switch between351        /// the two.352        /// </summary>353        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]354        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]355        [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSL")]356        public SwitchParameter UseSSL { get; set; }357 358        /// <summary>359        /// Session options.360        /// </summary>361        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerInstanceIdParameterSet)]362        [Parameter(ParameterSetName = ReceivePSSessionCommand.ComputerSessionNameParameterSet)]363        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)]364        [Parameter(ParameterSetName = ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)]365        public PSSessionOption SessionOption { get; set; }366 367        #endregion368 369        #region Cmdlet Overrides370 371        /// <summary>372        /// Process input.373        /// </summary>374        protected override void ProcessRecord()375        {376            if (ParameterSetName == ReceivePSSessionCommand.ComputerSessionNameParameterSet ||377                ParameterSetName == ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)378            {379                QueryForAndConnectCommands(Name, Guid.Empty);380            }381            else if (ParameterSetName == ReceivePSSessionCommand.ComputerInstanceIdParameterSet ||382                     ParameterSetName == ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet)383            {384                QueryForAndConnectCommands(string.Empty, InstanceId);385            }386            else387            {388                GetAndConnectSessionCommand();389            }390        }391 392        /// <summary>393        /// User has signaled a stop for this cmdlet.394        /// </summary>395        protected override void StopProcessing()396        {397            RemotePipeline tmpPipeline;398            Job tmpJob;399 400            lock (_syncObject)401            {402                _stopProcessing = true;403                tmpPipeline = _remotePipeline;404                tmpJob = _job;405            }406 407            tmpPipeline?.StopAsync();408            tmpJob?.StopJob();409        }410 411        #endregion412 413        #region Private Methods414 415        /// <summary>416        /// Queries the remote computer for the specified session, creates a disconnected417        /// session object, connects the runspace/command and collects command data.418        /// Command output is either returned (OutTarget.Host) or collected419        /// in a job object that is returned (OutTarget.Job).420        /// </summary>421        /// <param name="name">Name of session to find.</param>422        /// <param name="instanceId">Instance Id of session to find.</param>423        private void QueryForAndConnectCommands(string name, Guid instanceId)424        {425            WSManConnectionInfo connectionInfo = GetConnectionObject();426 427            // Retrieve all disconnected runspaces on the remote computer.428            Runspace[] runspaces;429            try430            {431                runspaces = Runspace.GetRunspaces(connectionInfo, this.Host, QueryRunspaces.BuiltInTypesTable);432            }433            catch (System.Management.Automation.RuntimeException e)434            {435                int errorCode;436                string msg = StringUtil.Format(RemotingErrorIdStrings.QueryForRunspacesFailed, connectionInfo.ComputerName,437                    QueryRunspaces.ExtractMessage(e.InnerException, out errorCode));438                string FQEID = WSManTransportManagerUtils.GetFQEIDFromTransportError(errorCode, "ReceivePSSessionQueryForSessionFailed");439                Exception reason = new RuntimeException(msg, e.InnerException);440                ErrorRecord errorRecord = new ErrorRecord(reason, FQEID, ErrorCategory.InvalidOperation, connectionInfo);441                WriteError(errorRecord);442                return;443            }444 445            // Convert configuration name into shell Uri for comparison.446            string shellUri = null;447            if (!string.IsNullOrEmpty(ConfigurationName))448            {449                shellUri = ConfigurationName.Contains(WSManNativeApi.ResourceURIPrefix, StringComparison.OrdinalIgnoreCase)450                    ? ConfigurationName451                    : WSManNativeApi.ResourceURIPrefix + ConfigurationName;452            }453 454            // Connect selected runspace/command and direct command output to host455            // or job objects.456            foreach (Runspace runspace in runspaces)457            {458                if (_stopProcessing)459                {460                    break;461                }462 463                // Filter returned runspaces by ConfigurationName if provided.464                if (shellUri != null)465                {466                    // Compare with returned shell Uri in connection info.467                    WSManConnectionInfo wsmanConnectionInfo = runspace.ConnectionInfo as WSManConnectionInfo;468                    if (wsmanConnectionInfo != null &&469                        !shellUri.Equals(wsmanConnectionInfo.ShellUri, StringComparison.OrdinalIgnoreCase))470                    {471                        continue;472                    }473                }474 475                // Find specified session.476                bool haveMatch = false;477                if (!string.IsNullOrEmpty(name) &&478                    string.Equals(name, ((RemoteRunspace)runspace).RunspacePool.RemoteRunspacePoolInternal.Name, StringComparison.OrdinalIgnoreCase))479                {480                    // Selected by friendly name.481                    haveMatch = true;482                }483                else if (instanceId.Equals(runspace.InstanceId))484                {485                    // Selected by instance Id (note that session/runspace/runspacepool instanceIds are identical.)486                    haveMatch = true;487                }488 489                if (haveMatch &&490                    ShouldProcess(((RemoteRunspace)runspace).PSSessionName, VerbsCommunications.Receive))491                {492                    // Check the local repository for an existing viable session.493                    PSSession locSession = this.RunspaceRepository.GetItem(runspace.InstanceId);494 495                    // Connect the session here.  If it fails (connectedSession == null) revert to the496                    // reconstruct method.497                    Exception ex;498                    PSSession connectedSession = ConnectSession(locSession, out ex);499 500                    if (connectedSession != null)501                    {502                        // Make sure that this connected session is included in the PSSession repository.503                        // If it already exists then replace it because we want the latest/connected session in the repository.504                        this.RunspaceRepository.AddOrReplace(connectedSession);505 506                        // Since we have a local runspace we will do a *reconnect* operation and will507                        // need the corresponding job object.508                        PSRemotingJob job = FindJobForSession(connectedSession);509                        if (this.OutTarget == OutTarget.Host)510                        {511                            ConnectSessionToHost(connectedSession, job);512                        }513                        else514                        {515                            // Connection to Job is default option.516                            ConnectSessionToJob(connectedSession, job);517                        }518                    }519                    else520                    {521                        // Otherwise create a new session from the queried runspace object.522                        // This will be a *reconstruct* operation.523                        // Create and connect session.524                        PSSession newSession = new PSSession(runspace as RemoteRunspace);525                        connectedSession = ConnectSession(newSession, out ex);526                        if (connectedSession != null)527                        {528                            // Try to reuse the existing local repository PSSession object.529                            if (locSession != null)530                            {531                                connectedSession = locSession.InsertRunspace(connectedSession.Runspace as RemoteRunspace) ? locSession : connectedSession;532                            }533 534                            // Make sure that this connected session is included in the PSSession repository.535                            // If it already exists then replace it because we want the latest/connected session in the repository.536                            this.RunspaceRepository.AddOrReplace(connectedSession);537 538                            if (this.OutTarget == OutTarget.Job)539                            {540                                ConnectSessionToJob(connectedSession);541                            }542                            else543                            {544                                // Connection to Host is default option.545                                ConnectSessionToHost(connectedSession);546                            }547                        }548                        else549                        {550                            string message = StringUtil.Format(RemotingErrorIdStrings.RunspaceCannotBeConnected, newSession.Name);551                            WriteError(new ErrorRecord(new ArgumentException(message, ex), "ReceivePSSessionCannotConnectSession",552                                       ErrorCategory.InvalidOperation, newSession));553                        }554                    }555 556                    break;557                }558            }559        }560 561        private WSManConnectionInfo GetConnectionObject()562        {563            WSManConnectionInfo connectionInfo = new WSManConnectionInfo();564 565            if (ParameterSetName == ReceivePSSessionCommand.ComputerSessionNameParameterSet ||566                ParameterSetName == ReceivePSSessionCommand.ComputerInstanceIdParameterSet)567            {568                // Create the WSManConnectionInfo object for the specified computer name.569                string scheme = UseSSL.IsPresent ? WSManConnectionInfo.HttpsScheme : WSManConnectionInfo.HttpScheme;570 571                connectionInfo.Scheme = scheme;572                connectionInfo.ComputerName = ResolveComputerName(ComputerName);573                connectionInfo.AppName = ApplicationName;574                connectionInfo.ShellUri = ConfigurationName;575                connectionInfo.Port = Port;576                if (CertificateThumbprint != null)577                {578                    connectionInfo.CertificateThumbprint = CertificateThumbprint;579                }580                else581                {582                    connectionInfo.Credential = Credential;583                }584 585                connectionInfo.AuthenticationMechanism = Authentication;586                UpdateConnectionInfo(connectionInfo);587            }588            else589            {590                connectionInfo.ConnectionUri = ConnectionUri;591                connectionInfo.ShellUri = ConfigurationName;592                if (CertificateThumbprint != null)593                {594                    connectionInfo.CertificateThumbprint = CertificateThumbprint;595                }596                else597                {598                    connectionInfo.Credential = Credential;599                }600 601                connectionInfo.AuthenticationMechanism = Authentication;602                UpdateConnectionInfo(connectionInfo);603            }604 605            return connectionInfo;606        }607 608        /// <summary>609        /// Updates connection info with the data read from cmdlet's parameters.610        /// </summary>611        /// <param name="connectionInfo"></param>612        private void UpdateConnectionInfo(WSManConnectionInfo connectionInfo)613        {614            if (ParameterSetName != ReceivePSSessionCommand.ConnectionUriInstanceIdParameterSet &&615                ParameterSetName != ReceivePSSessionCommand.ConnectionUriSessionNameParameterSet)616            {617                // uri redirection is supported only with URI parameter set618                connectionInfo.MaximumConnectionRedirectionCount = 0;619            }620 621            if (!_allowRedirection)622            {623                // uri redirection required explicit user consent624                connectionInfo.MaximumConnectionRedirectionCount = 0;625            }626 627            // Update the connectionInfo object with passed in session options.628            if (SessionOption != null)629            {630                connectionInfo.SetSessionOptions(SessionOption);631            }632        }633 634        /// <summary>635        /// Gets the PSSession object to connect based on Id, Name, etc.636        /// Connects the running command associated with the PSSession runspace object.637        /// Command output is either returned (OutTarget.Host) or collected638        /// in a job object that is returned (OutTarget.Job).639        /// </summary>640        private void GetAndConnectSessionCommand()641        {642            PSSession session = null;643 644            if (ParameterSetName == ReceivePSSessionCommand.SessionParameterSet)645            {646                session = Session;647            }648            else if (ParameterSetName == ReceivePSSessionCommand.IdParameterSet)649            {650                session = GetSessionById(Id);651                if (session == null)652                {653                    WriteInvalidArgumentError(PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedSessionId,654                                              RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedSessionId,655                                              Id);656 657                    return;658                }659            }660            else if (ParameterSetName == ReceivePSSessionCommand.NameParameterSet)661            {662                session = GetSessionByName(Name);663                if (session == null)664                {665                    WriteInvalidArgumentError(PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedName,666                                              RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedName,667                                              Name);668 669                    return;670                }671            }672            else if (ParameterSetName == ReceivePSSessionCommand.InstanceIdParameterSet)673            {674                session = GetSessionByInstanceId(InstanceId);675                if (session == null)676                {677                    WriteInvalidArgumentError(PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedRunspaceId,678                                              RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedRunspaceId,679                                              InstanceId);680 681                    return;682                }683            }684            else685            {686                Dbg.Assert(false, "Invalid Parameter Set");687            }688 689            // PS session disconnection is not supported for VM/Container sessions.690            if (session.ComputerType != TargetMachineType.RemoteMachine)691            {692                string msg = StringUtil.Format(RemotingErrorIdStrings.RunspaceCannotBeReceivedForVMContainerSession,693                    session.Name, session.ComputerName, session.ComputerType);694                Exception reason = new PSNotSupportedException(msg);695                ErrorRecord errorRecord = new ErrorRecord(reason, "CannotReceiveVMContainerSession", ErrorCategory.InvalidOperation, session);696                WriteError(errorRecord);697                return;698            }699 700            if (ShouldProcess(session.Name, VerbsCommunications.Receive))701            {702                Exception ex;703                if (ConnectSession(session, out ex) == null)704                {705                    // Unable to connect runspace.  If this was a *reconnect* runspace then try706                    // obtaining a connectable runspace directly from the server and do a707                    // *reconstruct* connect.708                    PSSession oldSession = session;709                    session = TryGetSessionFromServer(oldSession);710                    if (session == null)711                    {712                        // No luck.  Return error.713                        string message = StringUtil.Format(RemotingErrorIdStrings.RunspaceCannotBeConnected, oldSession.Name);714                        WriteError(new ErrorRecord(new ArgumentException(message, ex), "ReceivePSSessionCannotConnectSession",715                                   ErrorCategory.InvalidOperation, oldSession));716 717                        return;718                    }719                }720 721                // Look to see if there exists a job associated with this runspace.722                // If so then we use this job object, unless the user explicitly specifies723                // output to host.724                PSRemotingJob job = FindJobForSession(session);725                if (job != null)726                {727                    // Default is to route data to job.728                    if (OutTarget == OutTarget.Host)729                    {730                        // This performs a *reconstruct* connection scenario where a new731                        // pipeline object is created and connected.732                        ConnectSessionToHost(session, job);733                    }734                    else735                    {736                        // This preforms a *reconnect* scenario where the existing job737                        // and runspace objects are reconnected.738                        ConnectSessionToJob(session, job);739                    }740                }741                else742                {743                    // Default is to route data to host.744                    if (OutTarget == OutTarget.Job)745                    {746                        // This performs a *reconstruct* connection scenario where new747                        // pipeline/job objects are created and connected.748                        ConnectSessionToJob(session);749                    }750                    else751                    {752                        // This performs a *reconstruct* connection scenario where a new753                        // pipeline object is created and connected.754                        ConnectSessionToHost(session);755                    }756                }757 758                // Make sure that if this session is successfully connected that it is included759                // in the PSSession repository.  If it already exists then replace it because we760                // want the latest/connected session in the repository.761                if (session.Runspace.RunspaceStateInfo.State != RunspaceState.Disconnected)762                {763                    this.RunspaceRepository.AddOrReplace(session);764                }765            }766        }767 768        private bool CheckForDebugMode(PSSession session, bool monitorAvailabilityChange)769        {770            RemoteRunspace remoteRunspace = session.Runspace as RemoteRunspace;771            if (remoteRunspace.RunspaceAvailability == RunspaceAvailability.RemoteDebug)772            {773                DisconnectAndStopRunningCmds(remoteRunspace);774                WriteDebugStopWarning();775                return true;776            }777 778            if (monitorAvailabilityChange)779            {780                // Monitor runspace availability transition to RemoteDebug781                remoteRunspace.AvailabilityChanged += HandleRunspaceAvailabilityChanged;782            }783 784            return false;785        }786 787        private void HandleRunspaceAvailabilityChanged(object sender, RunspaceAvailabilityEventArgs e)788        {789            if ((e.RunspaceAvailability == RunspaceAvailability.RemoteDebug))790            {791                RemoteRunspace remoteRunspace = sender as RemoteRunspace;792                remoteRunspace.AvailabilityChanged -= HandleRunspaceAvailabilityChanged;793 794                DisconnectAndStopRunningCmds(remoteRunspace);795            }796        }797 798        private void DisconnectAndStopRunningCmds(RemoteRunspace remoteRunspace)799        {800            // Disconnect runspace to stop command from running and to allow reconnect801            // via the Enter-PSSession cmdlet.802            if (remoteRunspace.RunspaceStateInfo.State == RunspaceState.Opened)803            {804                Job job;805                ManualResetEvent stopPipelineReceive;806                lock (_syncObject)807                {808                    job = _job;809                    stopPipelineReceive = _stopPipelineReceive;810                }811 812                remoteRunspace.Disconnect();813 814                try815                {816                    stopPipelineReceive?.Set();817                }818                catch (ObjectDisposedException) { }819 820                job?.StopJob();821            }822        }823 824        private void WriteDebugStopWarning()825        {826            WriteWarning(827                GetMessage(RemotingErrorIdStrings.ReceivePSSessionInDebugMode));828            WriteObject(string.Empty);829        }830 831        /// <summary>832        /// Connects session, retrieves command output data and writes to host.833        /// </summary>834        /// <param name="session">PSSession object.</param>835        /// <param name="job">Job object associated with session.</param>836        private void ConnectSessionToHost(PSSession session, PSRemotingJob job = null)837        {838            RemoteRunspace remoteRunspace = session.Runspace as RemoteRunspace;839            Dbg.Assert(remoteRunspace != null, "PS sessions can only contain RemoteRunspace type.");840 841            if (job != null)842            {843                // If we have a job object associated with the session then this means844                // the user explicitly chose to connect and return data synchronously.845 846                // Reconnect the job object and stream data to host.847                lock (_syncObject) { _job = job; _stopPipelineReceive = new ManualResetEvent(false); }848 849                using (_stopPipelineReceive)850                using (job)851                {852                    Job childJob = job.ChildJobs[0];853                    job.ConnectJobs();854                    if (CheckForDebugMode(session, true))855                    {856                        return;857                    }858 859                    do860                    {861                        // Retrieve and display results from child job as they become862                        // available.863                        int index = WaitHandle.WaitAny(new WaitHandle[] {864                            _stopPipelineReceive,865                            childJob.Results.WaitHandle });866 867                        foreach (var result in childJob.ReadAll())868                        {869                            result?.WriteStreamObject(this);870                        }871 872                        if (index == 0)873                        {874                            WriteDebugStopWarning();875                            return;876                        }877                    }878                    while (!job.IsFinishedState(job.JobStateInfo.State));879                }880 881                lock (_syncObject) { _job = null; _stopPipelineReceive = null; }882 883                return;884            }885 886            // Otherwise this must be a new disconnected session object that has a running command887            // associated with it.888            if (remoteRunspace.RemoteCommand == null)889            {890                // There is no associated running command for this runspace, so we cannot proceed.891                // Check to see if session is in debug mode.892                CheckForDebugMode(session, false);893                return;894            }895 896            // Create a RemotePipeline object for this command and attempt to connect.897            lock (_syncObject)898            {899                _remotePipeline = (RemotePipeline)session.Runspace.CreateDisconnectedPipeline();900                _stopPipelineReceive = new ManualResetEvent(false);901            }902 903            using (_stopPipelineReceive)904            {905                using (_remotePipeline)906                {907                    // Connect to remote running command.908                    ManualResetEvent pipelineConnectedEvent = new ManualResetEvent(false);909                    using (pipelineConnectedEvent)910                    {911                        _remotePipeline.StateChanged += (sender, args) =>912                            {913                                if (pipelineConnectedEvent != null &&914                                    (args.PipelineStateInfo.State == PipelineState.Running ||915                                     args.PipelineStateInfo.State == PipelineState.Stopped ||916                                     args.PipelineStateInfo.State == PipelineState.Failed))917                                {918                                    pipelineConnectedEvent.Set();919                                }920                            };921                        _remotePipeline.ConnectAsync();922                        pipelineConnectedEvent.WaitOne();923                    }924 925                    pipelineConnectedEvent = null;926 927                    if (CheckForDebugMode(session, true))928                    {929                        return;930                    }931 932                    // Wait for remote command to complete, while writing any available data.933                    while (!_remotePipeline.Output.EndOfPipeline)934                    {935                        if (_stopProcessing)936                        {937                            break;938                        }939 940                        int index = WaitHandle.WaitAny(new WaitHandle[] {941                            _stopPipelineReceive,942                            _remotePipeline.Output.WaitHandle });943 944                        if (index == 0)945                        {946                            WriteDebugStopWarning();947                            return;948                        }949 950                        while (_remotePipeline.Output.Count > 0)951                        {952                            if (_stopProcessing)953                            {954                                break;955                            }956 957                            PSObject psObject = _remotePipeline.Output.Read();958                            WriteRemoteObject(psObject, session);959                        }960                    }961 962                    // Write pipeline object errors.963                    if (_remotePipeline.Error.Count > 0)964                    {965                        while (!_remotePipeline.Error.EndOfPipeline)966                        {967                            object errorObj = _remotePipeline.Error.Read();968                            if (errorObj is Collection<ErrorRecord>)969                            {970                                Collection<ErrorRecord> errorCollection = (Collection<ErrorRecord>)errorObj;971                                foreach (ErrorRecord errorRecord in errorCollection)972                                {973                                    WriteError(errorRecord);974                                }975                            }976                            else if (errorObj is ErrorRecord)977                            {978                                WriteError((ErrorRecord)errorObj);979                            }980                            else981                            {982                                Dbg.Assert(false, "Objects in pipeline Error collection must be ErrorRecord type.");983                            }984                        }985                    }986 987                    // Wait for pipeline to finish.988                    int wIndex = WaitHandle.WaitAny(new WaitHandle[] {989                            _stopPipelineReceive,990                            _remotePipeline.PipelineFinishedEvent });991 992                    if (wIndex == 0)993                    {994                        WriteDebugStopWarning();995                        return;996                    }997 998                    // Set the runspace RemoteCommand to null.  It is not needed anymore and it999                    // allows the runspace to become available after pipeline completes.1000                    remoteRunspace.RunspacePool.RemoteRunspacePoolInternal.ConnectCommands = null;1001 1002                    // Check for any terminating errors to report.1003                    if (_remotePipeline.PipelineStateInfo.State == PipelineState.Failed)1004                    {1005                        Exception reason = _remotePipeline.PipelineStateInfo.Reason;1006                        string msg;1007                        if (reason != null && !string.IsNullOrEmpty(reason.Message))1008                        {1009                            msg = StringUtil.Format(RemotingErrorIdStrings.PipelineFailedWithReason, reason.Message);1010                        }1011                        else1012                        {1013                            msg = RemotingErrorIdStrings.PipelineFailedWithoutReason;1014                        }1015 1016                        ErrorRecord errorRecord = new ErrorRecord(new RuntimeException(msg, reason),1017                                                            "ReceivePSSessionPipelineFailed",1018                                                            ErrorCategory.OperationStopped,1019                                                            _remotePipeline1020                                                            );1021 1022                        WriteError(errorRecord);1023                    }1024                }1025            }1026 1027            lock (_syncObject) { _remotePipeline = null; _stopPipelineReceive = null; }1028        }1029 1030        /// <summary>1031        /// Helper method to append computer name and session GUID1032        /// note properties to the PSObject before it is written.1033        /// </summary>1034        /// <param name="psObject">PSObject.</param>1035        /// <param name="session">PSSession.</param>1036        private void WriteRemoteObject(1037            PSObject psObject,1038            PSSession session)1039        {1040            if (psObject == null)1041            {1042                return;1043            }1044 1045            // Add note properties for this session if they don't already exist.1046            if (psObject.Properties[RemotingConstants.ComputerNameNoteProperty] == null)1047            {1048                psObject.Properties.Add(new PSNoteProperty(RemotingConstants.ComputerNameNoteProperty, session.ComputerName));1049            }1050 1051            if (psObject.Properties[RemotingConstants.RunspaceIdNoteProperty] == null)1052            {1053                psObject.Properties.Add(new PSNoteProperty(RemotingConstants.RunspaceIdNoteProperty, session.InstanceId));1054            }1055 1056            if (psObject.Properties[RemotingConstants.ShowComputerNameNoteProperty] == null)1057            {1058                psObject.Properties.Add(new PSNoteProperty(RemotingConstants.ShowComputerNameNoteProperty, true));1059            }1060 1061            WriteObject(psObject);1062        }1063 1064        /// <summary>1065        /// Connects session, collects command output data in a job object.1066        /// If a PSRemotingJob object is passed in then that job will be1067        /// (re)connected.  Otherwise a new job object will be created that1068        /// will be connected to the session's running command.1069        /// </summary>1070        /// <param name="session">PSSession object.</param>1071        /// <param name="job">Job object to connect to.</param>1072        private void ConnectSessionToJob(PSSession session, PSRemotingJob job = null)1073        {1074            // Otherwise create a new job object in the disconnected state for this1075            // session and then connect it.1076            bool newJobCreated = false;1077            if (job == null)1078            {1079                // The PSRemoting job object uses helper objects to track remote command execution.1080                List<IThrottleOperation> helpers = new List<IThrottleOperation>();1081 1082                // Create the remote pipeline object that will represent the running command1083                // on the server machine.  This object will be in the disconnected state.1084                Pipeline remotePipeline = session.Runspace.CreateDisconnectedPipeline();1085 1086                // Create a disconnected runspace helper for this remote command.1087                helpers.Add(new DisconnectedJobOperation(remotePipeline));1088 1089                // Create the job object in a disconnected state.  Note that the job name1090                // will be autogenerated.1091                job = new PSRemotingJob(helpers, 0, JobName, false);1092                job.PSJobTypeName = InvokeCommandCommand.RemoteJobType;1093                job.HideComputerName = false;1094                newJobCreated = true;1095            }1096 1097            if (job.JobStateInfo.State == JobState.Disconnected)1098            {1099                // Connect the job to the remote command running on the server.1100                job.ConnectJob(session.Runspace.InstanceId);1101 1102                // Add the created job to the store if it was connected successfully.1103                if (newJobCreated)1104                {1105                    JobRepository.Add(job);1106                }1107            }1108 1109            if (CheckForDebugMode(session, true))1110            {1111                return;1112            }1113 1114            // Write the job object to output.1115            WriteObject(job);1116        }1117 1118        /// <summary>1119        /// Helper method to connect the runspace.  If the session/runspace can't1120        /// be connected or fails to be connected then a null PSSessionobject is1121        /// returned.1122        /// </summary>1123        /// <param name="session">Session to connect.</param>1124        /// <param name="ex">Optional exception object.</param>1125        /// <returns>Connected session or null.</returns>1126        private static PSSession ConnectSession(PSSession session, out Exception ex)1127        {1128            ex = null;1129 1130            if (session == null ||1131                (session.Runspace.RunspaceStateInfo.State != RunspaceState.Opened &&1132                 session.Runspace.RunspaceStateInfo.State != RunspaceState.Disconnected))1133            {1134                return null;1135            }1136            else if (session.Runspace.RunspaceStateInfo.State == RunspaceState.Opened)1137            {1138                return session;1139            }1140 1141            try1142            {1143                session.Runspace.Connect();1144            }1145            catch (PSInvalidOperationException e)1146            {1147                ex = e;1148            }1149            catch (InvalidRunspaceStateException e)1150            {1151                ex = e;1152            }1153            catch (RuntimeException e)1154            {1155                ex = e;1156            }1157 1158            return (ex == null) ? session : null;1159        }1160 1161        /// <summary>1162        /// Helper method to attempt to retrieve a disconnected runspace object1163        /// from the server, based on the provided session object.1164        /// </summary>1165        /// <param name="session">PSSession session object.</param>1166        /// <returns>PSSession disconnected runspace object.</returns>1167        private PSSession TryGetSessionFromServer(PSSession session)1168        {1169            if (session.Runspace is not RemoteRunspace remoteRunspace)1170            {1171                return null;1172            }1173 1174            remoteRunspace = null;1175            Runspace[] runspaces = Runspace.GetRunspaces(session.Runspace.ConnectionInfo, this.Host, QueryRunspaces.BuiltInTypesTable);1176            foreach (Runspace runspace in runspaces)1177            {1178                if (runspace.InstanceId == session.Runspace.InstanceId)1179                {1180                    remoteRunspace = runspace as RemoteRunspace;1181                    break;1182                }1183            }1184 1185            if (remoteRunspace != null)1186            {1187                // Try inserting connected runspace into existing PSSession.1188                session = session.InsertRunspace(remoteRunspace) ? session : new PSSession(remoteRunspace);1189                return session;1190            }1191 1192            return null;1193        }1194 1195        /// <summary>1196        /// Helper method to search the local PS client job repository1197        /// for a job associated with the provided session.1198        /// </summary>1199        /// <param name="session">PSSession object.</param>1200        /// <returns>Associated job object from the job repository.</returns>

Showing the first 1,200 of 1343 lines. Download the file for the rest.