fabric cannot execute remote command on windows

2019-04-09 11:02发布

问题:

I'm using fabric to run some command on a remote windows 7 system. and what i did was like:

env.hosts=['192.168.91.235']
env.user='test'
env.password='123456'

def test_windows():
    run("ifconfig",shell=False)
    pass

And it works for "ipconfig" and outputs the network infors of remote system, so i'm sure the ssh connection is OK. But it does not work for any other command i tried, like "cd", "echo hello". The error was :

out: Unable to execute command or shell on remote system: Failed to Execute process.

And i want to run a windows shell script remotely, so should i do?

P.S. the commands "cd" "echo hello" works if i connect the windows via putty.

[Update]

I realize that fabric is using env.shell to interpret the command i passed, now my question is: can is specify a windows shell to fabric env.shell? and how?

[Update again]

I was assigning "cmd.exe" to env.shell and it was stuck at executing "cmd.exe". After a few attempts env.shell="cmd.exe /c" eventually works. now i can execute dir, echo remotely via fabric.

[Update after it's finally solved:]

I'm not sure if my solution is flawed, it goes well till now.

My solution is using msys on windows + fabric on linux + freesshd on windows as sshserver.

msys on windows provides a "bash", as Andrew Walker mentioned below, fabric expects "bash" and performs excellently on it. although in [update again] above, fabric can also live with cmd.exe /c and execute windows commands on it.

To assign msys bash/shell to fabric, user should tell env specifically how to find the bash

env.shell='cmd.exe /c c:/msys/1.0/bin/sh.exe -l -c'

cmd.exe /c tell fabric the following string should be execute as a "command" in cmd.exe, /c after cmd.exe indicates a command in windows cmd contenxt, it's like cmd.exe /c "command"

then c:/msys/1.0/bin/sh -l -c is executed by cmd.exe and fabric is executing msys shell. I'm not sure what does -l do, the msys shell cannot find fakelinuxcommand.exe in bin folder without -l, so i made the conclusion that -l helps with the environment. -c is similar with /c in cmd.exe /c, indicating the following string as a command of c:/msys/1.0/bin/sh, so the following stuff passed to ssh client is executed as a command in msys shell.

An integrate example to make it clear:

env.password='123456'
env.user='test'
env.hosts=['test@192.168.91.238']
env.shell='cmd.exe /c c:/msys/1.0/bin/sh.exe -l -c'

def run_shell_command(command):
    return run(command,pty=False)

the argument command in function run_shell_command will be concatenate with env.shell and executed by msys shell.

[My Conclusion]

I don't think fabric cannot work without a 'bash like' pseudo terminal. In [update again], fabric in linux can execute command in a remote windows's cmd.exe. And that is enough in some scenarios where only remote winodws are present. msys provides a linux bash to allow me execute same shell scripts on both remote windows and remote linux from a local linux.

回答1:

Fabric really is expecting a bash (or at least bash-like) shell on the remote machine.

The easiest way to get fabric to run commands on a remote windows machine is to install an appropriate shell. For example, an install of cygwin includes such a shell by default.



回答2:

I agree with Martian Puss Conclusion, that is "Fabric can work without a 'bash-like' shell".

I have installed FreeSSHd software into my Windows 7 machine (running as a service), and I have granted access to the windows shell for the "sistemas" user.

Then, the following Fabric code can be used to invoke commands remotely on that shell (like systeminfo):

from fabric.api import env, run

env.hosts=["sistemas@cliente03"]
def test_win():
    run("systeminfo", shell=False, pty=False)

Pay special attention to the shell=False argument which is the key to make this working properly.

If we run it, this is what we get:

[sistemas@cliente01 ~]$ fab test_win
[sistemas@cliente03] Executing task 'test_win'
[sistemas@cliente03] run: systeminfo
[sistemas@cliente03] Login password for 'sistemas': 
[sistemas@cliente03] out: 
[sistemas@cliente03] out: Host Name:                 RP_CLIENTE03
[sistemas@cliente03] out: OS Name:                   Microsoft Windows 7 Professional 
[sistemas@cliente03] out: OS Version:                6.1.7601 Service Pack 1 Build 7601
[sistemas@cliente03] out: OS Manufacturer:           Microsoft Corporation
[sistemas@cliente03] out: OS Configuration:          Standalone Workstation
...
[sistemas@cliente03] out: 


Done.
Disconnecting from cliente03... done.