/// <summary>
        /// Dispose.
        /// </summary>
        public void Dispose()
        {
            lock (_syncObject)
            {
                if (IsDisposed)
                {
                    return;
                }

                IsDisposed = true;
            }

            if (TextReader != null)
            {
                try { TextReader.Dispose(); }
                catch (ObjectDisposedException) { }

                TextReader = null;
            }

            if (TextWriter != null)
            {
                try { TextWriter.Dispose(); }
                catch (ObjectDisposedException) { }

                TextWriter = null;
            }

            if (Stream != null)
            {
                try { Stream.Dispose(); }
                catch (ObjectDisposedException) { }
            }

            if (HyperVSocket != null)
            {
                try { HyperVSocket.Dispose(); }
                catch (ObjectDisposedException) { }
            }
        }
 public void Close()
 {
     Stream.Dispose();
     HyperVSocket.Dispose();
 }
        /// <summary>
        /// Connect to Hyper-V socket server.  This is a blocking call until a
        /// connection occurs or the timeout time has elapsed.
        /// </summary>
        /// <param name="networkCredential">The credential used for authentication.</param>
        /// <param name="configurationName">The configuration name of the PS session.</param>
        /// <param name="isFirstConnection">Whether this is the first connection.</param>
        public bool Connect(
            NetworkCredential networkCredential,
            string configurationName,
            bool isFirstConnection)
        {
            bool result = false;

            //
            // Check invalid input and throw exception before setting up socket connection.
            // This check is done only in VM case.
            //
            if (isFirstConnection)
            {
                if (string.IsNullOrEmpty(networkCredential.UserName))
                {
                    throw new PSDirectException(
                              PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidUsername));
                }
            }

            HyperVSocket.Connect(EndPoint);

            if (HyperVSocket.Connected)
            {
                _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty,
                                     "Client connected.");

                Stream = new NetworkStream(HyperVSocket, true);

                if (isFirstConnection)
                {
                    if (string.IsNullOrEmpty(networkCredential.Domain))
                    {
                        networkCredential.Domain = "localhost";
                    }

                    bool emptyPassword      = string.IsNullOrEmpty(networkCredential.Password);
                    bool emptyConfiguration = string.IsNullOrEmpty(configurationName);

                    byte[] domain   = Encoding.Unicode.GetBytes(networkCredential.Domain);
                    byte[] userName = Encoding.Unicode.GetBytes(networkCredential.UserName);
                    byte[] password = Encoding.Unicode.GetBytes(networkCredential.Password);
                    byte[] response = new byte[4]; // either "PASS" or "FAIL"
                    string responseString;

                    //
                    // Send credential to VM so that PowerShell process inside VM can be
                    // created under the correct security context.
                    //
                    HyperVSocket.Send(domain);
                    HyperVSocket.Receive(response);

                    HyperVSocket.Send(userName);
                    HyperVSocket.Receive(response);

                    //
                    // We cannot simply send password because if it is empty,
                    // the vmicvmsession service in VM will block in recv method.
                    //
                    if (emptyPassword)
                    {
                        HyperVSocket.Send(Encoding.ASCII.GetBytes("EMPTYPW"));
                        HyperVSocket.Receive(response);
                        responseString = Encoding.ASCII.GetString(response);
                    }
                    else
                    {
                        HyperVSocket.Send(Encoding.ASCII.GetBytes("NONEMPTYPW"));
                        HyperVSocket.Receive(response);

                        HyperVSocket.Send(password);
                        HyperVSocket.Receive(response);
                        responseString = Encoding.ASCII.GetString(response);
                    }

                    //
                    // There are 3 cases for the responseString received above.
                    // - "FAIL": credential is invalid
                    // - "PASS": credential is valid, but PowerShell Direct in VM does not support configuration (Server 2016 TP4 and before)
                    // - "CONF": credential is valid, and PowerShell Direct in VM supports configuration (Server 2016 TP5 and later)
                    //

                    //
                    // Credential is invalid.
                    //
                    if (string.Equals(responseString, "FAIL", StringComparison.Ordinal))
                    {
                        HyperVSocket.Send(response);

                        throw new PSDirectException(
                                  PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential));
                    }

                    //
                    // If PowerShell Direct in VM supports configuration, send configuration name.
                    //
                    if (string.Equals(responseString, "CONF", StringComparison.Ordinal))
                    {
                        if (emptyConfiguration)
                        {
                            HyperVSocket.Send(Encoding.ASCII.GetBytes("EMPTYCF"));
                        }
                        else
                        {
                            HyperVSocket.Send(Encoding.ASCII.GetBytes("NONEMPTYCF"));
                            HyperVSocket.Receive(response);

                            byte[] configName = Encoding.Unicode.GetBytes(configurationName);
                            HyperVSocket.Send(configName);
                        }
                    }
                    else
                    {
                        HyperVSocket.Send(response);
                    }
                }

                TextReader           = new StreamReader(Stream);
                TextWriter           = new StreamWriter(Stream);
                TextWriter.AutoFlush = true;

                result = true;
            }
            else
            {
                _tracer.WriteMessage("RemoteSessionHyperVSocketClient", "Connect", Guid.Empty,
                                     "Client unable to connect.");

                result = false;
            }

            return(result);
        }