/// <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); }