Python input() unresponsive after plink
<p>On Windows, I'm running the following Python 3.5 script from <code>cmd.exe</code>:</p>

<pre><code>subprocess.run(['C:\\Program Files (x86)\\Putty\\plink.exe', 
                'root@server', '-P', '54022', '-i', 'key.ppk', 'exit'])     
input('Press Enter...')
</code></pre>

<p>But when it's time to press Enter, the console is unresponsive. <kbd>Enter</kbd> does nothing. Text can't be entered. <kbd>Ctrl+C</kbd> doesn't do anything either. Python has to be killed in the task manager.</p>

<p>I suspect <code>plink</code> is leaving the console in a bad state. Can I prevent or repair this? Or can I run the ssh command in its own console? That's not ideal, but it'll do.</p>

<p>Or maybe there's a better solution for running remote commands via SSH using Python?</p>

<p>When running the same <code>plink</code> command directly from <code>cmd</code> (no Python), it does remain responsive.</p>

<p>A process might modify the console state and then for some reason fail to restore the original state when it exits. If this is a problem, the easiest solution is to spawn the child process with its own console by adding the parameter <code>creationflags=subprocess.CREATE_NEW_CONSOLE</code>. </p>

<p>If that's not an option, or at least not a preferred option, you could instead capture the current modes of the console's input and screen buffer prior to running the program. Then restore the previous modes after the child exits. See <a href="https://msdn.microsoft.com/en-us/library/ms683167" rel="nofollow"><code>GetConsoleMode</code></a> and <a href="https://msdn.microsoft.com/en-us/library/ms686033" rel="nofollow"><code>SetConsoleMode</code></a> on MSDN. </p>

<p>Here's a context manager to restore the console's input and output modes. </p>

<pre><code>import ctypes
import msvcrt
import contextlib

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

kernel32.GetConsoleMode.errcheck = _check_bool
kernel32.SetConsoleMode.errcheck = _check_bool

@contextlib.contextmanager
def restore_console():
    if not kernel32.GetConsoleWindow():
        yield  # nothing to do
        return
    with open(r'\\.\CONIN$', 'r+') as coni:
        with open(r'\\.\CONOUT$', 'r+') as cono:
            hI = msvcrt.get_osfhandle(coni.fileno())
            hO = msvcrt.get_osfhandle(cono.fileno())
            imode = ctypes.c_ulong()
            omode = ctypes.c_ulong()
            kernel32.GetConsoleMode(hI, ctypes.byref(imode))
            kernel32.GetConsoleMode(hO, ctypes.byref(omode))
            yield
            try:
                kernel32.SetConsoleMode(hI, imode)
            finally:
                kernel32.SetConsoleMode(hO, omode)
</code></pre>

<p>This could be expanded to restore the input and output codepages via <code>GetConsoleCP</code>, <code>GetConsoleOutputCP</code>, <code>SetConsoleCP</code>, and <code>SetConsoleOutputCP</code>. It could also restore the screen dimensions, title, and so on. This is all global state in conhost.exe that a child process can meddle with. On the other hand, the console's input history and aliases are stored per attached executable, so you shouldn't have to restore them.</p>

python windows putty windows-console plink