I have an environment where I can SSH into a Linux machine via Cygwin, but not the other way around due to a security policy out of my control.

I need to automate tasks on the Windows machine but dictate these things to do from scripts or parameters PULL'd from the Linux machine (ie, a watched folder or web service).

How can I structure this so that I can keep an SSH connection open and upon detecting this remote variable change, trigger another Cygwin command on the Windows machine?

An example use case would be browser automation with parameters. While I could do this via a git repo and a recurring script that first syncs with latest code each time before running, I'd like to have more control, such as to force kill the executing thread via passing another variable or shell script down the line.

UPDATE: After all that, there was another method to change the Windows firewall which allowed port 22 connections, so this complicated case will thankfully not be required, but I like the suggestions listed below.

UPDATE: Seems the scenario still exists. Though getting direct access to the system via SSH allowed execution of tasks, these were sandboxed within the SSH user, not the network domain user that I wanted to run GUI tasks in (local Cygwin instance does not have the problems to execute within the domain user's GUI). See my answer below.

  • This sounds very complicated. Which problem are you trying to solve? For a Linux dev environment with a shared folder, many people like to use Vagrant, for example. – sr_ Nov 1 '13 at 6:55

Can you run sshd on the Windows machine? If yes then you could open a tunnel so that the Linux machine can send commands to the Windows machine like this:

ssh -R 2222: user@linuxmachine control-script

control-script would then contain all your checks and if something has to be executed on the Windows machine it would execute a command like this:

ssh -p 2222 user@localhost something.cmd
|improve this answer|||||
  • that sounds promising if Windows is the one initiating the tunnel, will give it a try – ljs.dev Nov 1 '13 at 17:22

I used something similar to troydj's answer, by simply using the watch command that executes a "checker" script that monitors for the existence of another script and executes it if discovered.

on Windows' Cygwin

watch -n 5 ~/checker.bash


if [ -f myscript.bash ]; then
 sh ~/myscript.bash
 echo 'checking...'

myscript.bash (example to launch Visual Studio 2012 via SSH)

/cygdrive/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio\ 11.0/Common7/IDE/devenv.exe
rm myscript.bash

On the Linux machine, I can develop away and create the scripts. Then when I want them executed on the Windows logged in user's GUI, I copy my script to the myscript.bash location, which once discovered by the "checker" script (being looped by the watch command), executes locally.

I added the last line to to the script to remove itself after execution, in this case.

This works really well for what I was aiming to do. Getting Cygwin to drive processes within a specific Windows user account via SSH connection is often tricky if not impossible without a workaround like this.

|improve this answer|||||

If you have Expect on your local Cygwin box, you can use it to ssh into your remote Linux box and watch for jobs in a spool directory. When new work is detected, the Expect script can suspend ssh, run local commands on the Cygwin system, and then resume ssh. It might look something like this (as a rudimentary first pass):


set timeout 10
log_user 1

spawn bash --login
expect -re {.*\$}       ;# Assumes a dollar sign in your prompt on local box

send "ssh remoteuser@your_remote_linux_box\r"
expect "*word:*"
send "REMOTE_PASSWORD\r"  ;# Bad security practice!!  For illustration purposes only.
expect -re {\r\n.*\$}     ;# Assumes a dollar sign in your prompt on your remote box
puts "Connected to remote system"

set i 0

while {$i < 5} {     ;# For now, we just loop 5 times. You might loop forever...
    send "ls ~/TasksSpoolDir | wc -l\r";
    expect -re "\r\n(\[0-9\]+)\r"
    set taskcount $expect_out(1,string)
    sleep 1
    if { $taskcount } {
            # Inspect remote job files from spool directory, for example, to determine what you want to do locally
            send "\r~\032"             ;# Send ~CTRL-Z to ssh
            expect "Stopped"
            send "pwd; ls; echo Do local tasks now.  Remove remote job files from spool directory...\r"
            sleep 1
            send "fg\r"                ;# Resume ssh.
            sleep 1
            send "\r\r"
            expect -re {\r\n.*\$}      ;# Assumes a dollar sign in your prompt on your remote box

    incr i
    sleep 1;  # Sleep however long between checks for new work from spool directory

send "exit\r"
expect -re {.*closed}
puts "Connection to remote host closed..."
send "exit\r"
expect "*"
puts "Local bash process closed..."

exit 0
|improve this answer|||||
  • thanks, that was the kind of solution I was envisioning, will try it out – ljs.dev Nov 1 '13 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.