/// <summary>
        /// Report that a new remote session (runspace) is created.
        /// </summary>
        internal static void ReportRemoteSessionCreated(
            System.Management.Automation.Runspaces.RunspaceConnectionInfo connectionInfo)
        {
            RemoteSessionType       sessionType       = RemoteSessionType.Unknown;
            RemoteConfigurationType configurationType = RemoteConfigurationType.Unknown;

            if (connectionInfo is System.Management.Automation.Runspaces.NewProcessConnectionInfo)
            {
                sessionType       = RemoteSessionType.LocalProcess;
                configurationType = RemoteConfigurationType.PSDefault;
            }
            else
            {
                System.Management.Automation.Runspaces.WSManConnectionInfo wsManConnectionInfo = connectionInfo as System.Management.Automation.Runspaces.WSManConnectionInfo;
                if (wsManConnectionInfo != null)
                {
                    sessionType = RemoteSessionType.WinRMRemote;

                    // Parse configuration name from ShellUri:
                    //  ShellUri = 'http://schemas.microsoft.com/powershell/Microsoft.PowerShell'
                    //  ConfigName = 'Microsoft.PowerShell'
                    string configurationName = wsManConnectionInfo.ShellUri;
                    if (!string.IsNullOrEmpty(configurationName))
                    {
                        int index = configurationName.LastIndexOf('/');
                        if (index > -1)
                        {
                            configurationName = configurationName.Substring(index + 1);
                        }
                    }

                    configurationType = GetConfigurationTypefromName(configurationName);
                }
                else
                {
                    System.Management.Automation.Runspaces.VMConnectionInfo vmConnectionInfo = connectionInfo as System.Management.Automation.Runspaces.VMConnectionInfo;
                    if (vmConnectionInfo != null)
                    {
                        sessionType       = RemoteSessionType.HyperVRemote;
                        configurationType = GetConfigurationTypefromName(vmConnectionInfo.ConfigurationName);
                    }
                    else
                    {
                        System.Management.Automation.Runspaces.ContainerConnectionInfo containerConnectionInfo = connectionInfo as System.Management.Automation.Runspaces.ContainerConnectionInfo;
                        if (containerConnectionInfo != null)
                        {
                            sessionType       = RemoteSessionType.ContainerRemote;
                            configurationType = GetConfigurationTypefromName(
                                (containerConnectionInfo.ContainerProc != null) ? containerConnectionInfo.ContainerProc.ConfigurationName : string.Empty);
                        }
                    }
                }
            }

            TelemetryWrapper.TraceMessage("PSNewRemoteSession", new
            {
                Type          = sessionType,
                Configuration = configurationType
            });
        }
        /// <summary>
        /// Constructor. This will create a new PrioritySendDataCollection which should be used to
        /// send data to the server.
        /// </summary>
        /// <param name="runspacePoolInstanceId">
        /// This is used for logging trace/operational crimson messages. Having this id in the logs 
        /// helps a user to map which transport is created for which runspace.
        /// </param>
        /// <param name="connectionInfo">
        /// Connection info to use while connecting to the remote machine.
        /// </param>
        /// <param name="cryptoHelper">crypto helper</param>
        /// <param name="sessionName">session friendly name</param>
        /// <exception cref="PSInvalidOperationException">
        /// 1. Create Session failed with a non-zero error code.
        /// </exception>
        internal WSManClientSessionTransportManager(Guid runspacePoolInstanceId,
            WSManConnectionInfo connectionInfo,
            PSRemotingCryptoHelper cryptoHelper, string sessionName) : base(runspacePoolInstanceId, cryptoHelper)
        {
            // Initialize WSMan instance
            WSManAPIData = new WSManAPIDataCommon();
            if (WSManAPIData.WSManAPIHandle == IntPtr.Zero)
            {
                throw new PSRemotingTransportException(
                    StringUtil.Format(RemotingErrorIdStrings.WSManInitFailed, WSManAPIData.ErrorCode));
            }
            Dbg.Assert(null != connectionInfo, "connectionInfo cannot be null");

            CryptoHelper = cryptoHelper;
            dataToBeSent.Fragmentor = base.Fragmentor;
            _sessionName = sessionName;

            // session transport manager can receive unlimited data..however each object is limited
            // by maxRecvdObjectSize. this is to allow clients to use a session for an unlimited time..
            // also the messages that can be sent to a session are limited and very controlled.
            // However a command transport manager can be restricted to receive only a fixed amount of data
            // controlled by maxRecvdDataSizeCommand..This is because commands can accept any number of input
            // objects.
            ReceivedDataCollection.MaximumReceivedDataSize = null;
            ReceivedDataCollection.MaximumReceivedObjectSize = connectionInfo.MaximumReceivedObjectSize;

            _onDataAvailableToSendCallback =
                new PrioritySendDataCollection.OnDataAvailableCallback(OnDataAvailableCallback);

            Initialize(connectionInfo.ConnectionUri, connectionInfo);
        }
        /// <summary>
        /// This is an internal constructor used by WSManClientSessionTransportManager.
        /// </summary>
        /// <param name="connectionInfo">
        /// connection info to be used for creating the command.
        /// </param>
        /// <param name="wsManShellOperationHandle">
        /// Shell operation handle in whose context this transport manager sends/receives
        /// data packets.
        /// </param>
        /// <param name="shell">
        /// The command to be sent to the remote end.
        /// </param>
        /// <param name="noInput">
        /// true if the command has input, false otherwise.
        /// </param>
        /// <param name="sessnTM">
        /// Session transport manager creating this command transport manager instance.
        /// Used by Command TM to apply session specific properties
        /// </param>
        internal WSManClientCommandTransportManager(WSManConnectionInfo connectionInfo,
            IntPtr wsManShellOperationHandle,
            ClientRemotePowerShell shell,
            bool noInput,
            WSManClientSessionTransportManager sessnTM) :
            base(shell, sessnTM.CryptoHelper, sessnTM)
        {
            Dbg.Assert(IntPtr.Zero != wsManShellOperationHandle, "Shell operation handle cannot be IntPtr.Zero.");
            Dbg.Assert(null != connectionInfo, "connectionInfo cannot be null");

            _wsManShellOperationHandle = wsManShellOperationHandle;

            // Apply quota limits.. allow for data to be unlimited..
            ReceivedDataCollection.MaximumReceivedDataSize = connectionInfo.MaximumReceivedDataSizePerCommand;
            ReceivedDataCollection.MaximumReceivedObjectSize = connectionInfo.MaximumReceivedObjectSize;
            _cmdLine = shell.PowerShell.Commands.Commands.GetCommandStringForHistory();
            _onDataAvailableToSendCallback =
                new PrioritySendDataCollection.OnDataAvailableCallback(OnDataAvailableCallback);
            _sessnTm = sessnTM;
            // Suspend queue on robust connections initiated event.
            sessnTM.RobustConnectionsInitiated += HandleRobustConnectionsIntiated;

            // Resume queue on robust connections completed event.
            sessnTM.RobustConnectionsCompleted += HandleRobusConnectionsCompleted;
        }
        /// <summary>
        /// Initializes the session.
        /// </summary>
        /// <param name="connectionUri">
        /// Uri to connect to.
        /// </param>
        /// <param name="connectionInfo">
        /// Connection info object used for retrieving credential, auth. mechanism etc.
        /// </param>
        /// <exception cref="PSInvalidOperationException">
        /// 1. Create Session failed with a non-zero error code.
        /// </exception>
        private void Initialize(Uri connectionUri, WSManConnectionInfo connectionInfo)
        {
            Dbg.Assert(null != connectionInfo, "connectionInfo cannot be null.");

            ConnectionInfo = connectionInfo;

            // this will generate: http://ComputerName:port/appname?PSVersion=<version>
            // PSVersion= pattern is needed to make Exchange compatible with PS V2 CTP3
            // release. Using the PSVersion= logic, Exchange R4 server will redirect
            // clients to an R3 endpoint.
            bool isSSLSpecified = false;
            string connectionStr = connectionUri.OriginalString;
            if ((connectionUri == connectionInfo.ConnectionUri) &&
                (connectionInfo.UseDefaultWSManPort))
            {
                connectionStr = WSManConnectionInfo.GetConnectionString(connectionInfo.ConnectionUri,
                    out isSSLSpecified);
            }

            // TODO: Remove this after RDS moved to $using
            string additionalUriSuffixString = string.Empty;
            if (PSSessionConfigurationData.IsServerManager)
            {
                additionalUriSuffixString = ";MSP=7a83d074-bb86-4e52-aa3e-6cc73cc066c8";
            }
            if (string.IsNullOrEmpty(connectionUri.Query))
            {
                // if there is no query string already, create one..see RFC 3986
                connectionStr = string.Format(CultureInfo.InvariantCulture,
                    "{0}?PSVersion={1}{2}",
                    // Trimming the last '/' as this will allow WSMan to
                    // properly apply URLPrefix. 
                    // Ex: http://localhost?PSVersion=2.0 will be converted
                    // to http://localhost:<port>/<urlprefix>?PSVersion=2.0
                    // by WSMan
                    connectionStr.TrimEnd('/'),
                    PSVersionInfo.PSVersion,
                    additionalUriSuffixString);
            }
            else
            {
                // if there is already a query string, append using & .. see RFC 3986
                connectionStr = string.Format(CultureInfo.InvariantCulture,
                       "{0};PSVersion={1}{2}",
                       connectionStr,
                       PSVersionInfo.PSVersion,
                       additionalUriSuffixString);
            }

            WSManNativeApi.BaseWSManAuthenticationCredentials authCredentials;
            // use certificate thumbprint for authentication
            if (connectionInfo.CertificateThumbprint != null)
            {
                authCredentials = new WSManNativeApi.WSManCertificateThumbprintCredentials(connectionInfo.CertificateThumbprint);
            }
            else
            {
                // use credential based authentication
                string userName = null;
                System.Security.SecureString password = null;
                if ((null != connectionInfo.Credential) && (!string.IsNullOrEmpty(connectionInfo.Credential.UserName)))
                {
                    userName = connectionInfo.Credential.UserName;
                    password = connectionInfo.Credential.Password;
                }

                WSManNativeApi.WSManUserNameAuthenticationCredentials userNameCredentials =
                    new WSManNativeApi.WSManUserNameAuthenticationCredentials(userName,
                        password,
                        connectionInfo.WSManAuthenticationMechanism);

                authCredentials = userNameCredentials;
            }

            // proxy related data
            WSManNativeApi.WSManUserNameAuthenticationCredentials proxyAuthCredentials = null;
            if (connectionInfo.ProxyCredential != null)
            {
                WSManNativeApi.WSManAuthenticationMechanism authMechanism = WSManNativeApi.WSManAuthenticationMechanism.WSMAN_FLAG_AUTH_NEGOTIATE;
                string userName = null;
                System.Security.SecureString password = null;

                switch (connectionInfo.ProxyAuthentication)
                {
                    case AuthenticationMechanism.Negotiate:
                        authMechanism = WSManNativeApi.WSManAuthenticationMechanism.WSMAN_FLAG_AUTH_NEGOTIATE;
                        break;
                    case AuthenticationMechanism.Basic:
                        authMechanism = WSManNativeApi.WSManAuthenticationMechanism.WSMAN_FLAG_AUTH_BASIC;
                        break;
                    case AuthenticationMechanism.Digest:
                        authMechanism = WSManNativeApi.WSManAuthenticationMechanism.WSMAN_FLAG_AUTH_DIGEST;
                        break;
                }

                if (!string.IsNullOrEmpty(connectionInfo.ProxyCredential.UserName))
                {
                    userName = connectionInfo.ProxyCredential.UserName;
                    password = connectionInfo.ProxyCredential.Password;
                }

                // use credential based authentication
                proxyAuthCredentials = new WSManNativeApi.WSManUserNameAuthenticationCredentials(userName, password, authMechanism);
            }

            WSManNativeApi.WSManProxyInfo proxyInfo = (ProxyAccessType.None == connectionInfo.ProxyAccessType) ?
                null :
                new WSManNativeApi.WSManProxyInfo(connectionInfo.ProxyAccessType, proxyAuthCredentials);

            int result = 0;

            try
            {
                result = WSManNativeApi.WSManCreateSession(WSManAPIData.WSManAPIHandle, connectionStr, 0,
                     authCredentials.GetMarshalledObject(),
                     (null == proxyInfo) ? IntPtr.Zero : (IntPtr)proxyInfo,
                     ref _wsManSessionHandle);
            }
            finally
            {
                // release resources
                if (null != proxyAuthCredentials)
                {
                    proxyAuthCredentials.Dispose();
                }

                if (null != proxyInfo)
                {
                    proxyInfo.Dispose();
                }

                if (null != authCredentials)
                {
                    authCredentials.Dispose();
                }
            }

            if (result != 0)
            {
                // Get the error message from WSMan
                string errorMessage = WSManNativeApi.WSManGetErrorMessage(WSManAPIData.WSManAPIHandle, result);

                PSInvalidOperationException exception = new PSInvalidOperationException(errorMessage);
                throw exception;
            }

            // set the packet size for this session
            int packetSize;
            WSManNativeApi.WSManGetSessionOptionAsDword(_wsManSessionHandle,
                WSManNativeApi.WSManSessionOption.WSMAN_OPTION_SHELL_MAX_DATA_SIZE_PER_MESSAGE_KB,
                out packetSize);
            // packet size returned is in KB. Convert this into bytes..
            Fragmentor.FragmentSize = packetSize << 10;

            // Get robust connections maximum retries time.
            WSManNativeApi.WSManGetSessionOptionAsDword(_wsManSessionHandle,
                WSManNativeApi.WSManSessionOption.WSMAN_OPTION_MAX_RETRY_TIME,
                out _maxRetryTime);

            this.dataToBeSent.Fragmentor = base.Fragmentor;
            _noCompression = !connectionInfo.UseCompression;
            _noMachineProfile = connectionInfo.NoMachineProfile;

            // set other WSMan session related defaults            
            if (isSSLSpecified)
            {
                // WSMan Port DCR related changes - BUG 542726
                // this session option will tell WSMan to use port for HTTPS from
                // config provider.
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_USE_SSL, 1);
            }
            if (connectionInfo.NoEncryption)
            {
                // send unencrypted messages
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_UNENCRYPTED_MESSAGES, 1);
            }
            // check if implicit credentials can be used for Negotiate
            if (connectionInfo.AllowImplicitCredentialForNegotiate)
            {
                result = WSManNativeApi.WSManSetSessionOption(_wsManSessionHandle,
                    WSManNativeApi.WSManSessionOption.WSMAN_OPTION_ALLOW_NEGOTIATE_IMPLICIT_CREDENTIALS,
                    new WSManNativeApi.WSManDataDWord(1));
            }
            if (connectionInfo.UseUTF16)
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_UTF16, 1);
            }

            if (connectionInfo.SkipCACheck)
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_SKIP_CA_CHECK, 1);
            }

            if (connectionInfo.SkipCNCheck)
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_SKIP_CN_CHECK, 1);
            }

            if (connectionInfo.SkipRevocationCheck)
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_SKIP_REVOCATION_CHECK, 1);
            }

            if (connectionInfo.IncludePortInSPN)
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_ENABLE_SPN_SERVER_PORT, 1);
            }

            // Set use interactive token flag based on EnableNetworkAccess property.
            SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_USE_INTERACTIVE_TOKEN,
                (connectionInfo.EnableNetworkAccess) ? 1 : 0);

            // set UI Culture for this session from current thread's UI Culture
            string currentUICulture = connectionInfo.UICulture.Name;
            if (!string.IsNullOrEmpty(currentUICulture))
            {
                // WSMan API cannot handle empty culture names
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_UI_LANGUAGE, currentUICulture);
            }

            // set Culture for this session from current thread's Culture
            string currentCulture = connectionInfo.Culture.Name;
            if (!string.IsNullOrEmpty(currentCulture))
            {
                SetWSManSessionOption(WSManNativeApi.WSManSessionOption.WSMAN_OPTION_LOCALE, currentCulture);
            }

            // set the PowerShell specific default client timeouts
            SetDefaultTimeOut(connectionInfo.OperationTimeout);
            SetConnectTimeOut(connectionInfo.OpenTimeout);
            SetCloseTimeOut(connectionInfo.CancelTimeout);
            SetSignalTimeOut(connectionInfo.CancelTimeout);
        }