From Python run WinSCP commands in console - python

I have to run a few commands of WinSCP from a Python class using subprocess.
The goal is to connect a local Windows machine and a Windows server with no FTP installed and download some files. This is what I tried
python
proc = subprocess.Popen(['WinSCP.exe', '/console', '/WAIT', user:password#ip:folder , '/WAIT','get' ,'*.txt'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
With this I get it to open the WinSCP console and connect to the server, but it doesn't execute the get command. Is the problem because the get is executed on the Windows console and not in the WinSCP console?
I also tried replacing winscp.exe /console for winscp.com /command.
Is there any way to do this?

If you want do without generating a script file, you can use a code like this:
import subprocess
process = subprocess.Popen(
['WinSCP.com', '/ini=nul', '/command',
'open ftp://user:password#example.com', 'get *.txt', 'exit'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for line in iter(process.stdout.readline, b''): # replace b'' with '' for Python 2
print(line.decode().rstrip())
The code uses:
/command switch to specify commands on WinSCP command-line;
winscp.com instead of winscp.exe, as winscp.com is a console application, so its output can be read by Python.
Though using the array for the arguments won't work, if there are spaces in command arguments (like file names). Then you will have to format the complete command-line yourself. See Python double quotes in subprocess.Popen aren't working when executing WinSCP scripting.

So when using the /script option you should specify a file containing the batch commands.
To specify all the commands on the command line as you're doing, use the /command option instead of /script.

Related

Running .bat file in Google Colab

I am trying to run a .bat file in my Google Colab notebook, howere I cannot seem to make it happen. Whenever I navigate to the folder the code says the directory or file does not exist.
from subprocess import Popen
p = Popen("batch.bat", cwd=r"/content/drive/MyDrive/sd/stable-diffusion/merge-models-main/")
stdout, stderr = p.communicate()
Colab is an Ubuntu Linux environment so it will struggle if the file to be run contains Windows like commands. If the file contains Linux shell commands then the following code illustrates how to execute these.
This cell makes a batch.bat file (purists would argue that it should be batch.sh).
# This is a Unix shell script
with open('batch.bat', 'w') as f:
f.write('var=$(date)\r\n')
f.write('echo "$var" > output.txt\r\n')
The file is placed into /content/ by default. If you want to use a file from your own Google Drive, you have to mount this yourself.
To execute the commands in the file do this. Note how Popen takes a list with the location of the file to execute as the second parameter.
from subprocess import Popen
p = Popen(["/bin/sh", "/content/batch.bat"])
stdout, stderr = p.communicate()
Look for the file output.txt and observe the timestamp in it. This should give an indication whether it is working.

Executing PowerShell commands with Python 3.5

I have been working on an issue that requires a Python script to run via the PowerShell command line. The script should pass the command to the command line and save the output. However, I'm running into an issue where some command line arguments are not recognized.
import subprocess
try:
output = subprocess.check_output\
(["Write-Output 'Hello world'"], shell=True)
# (["dir"], shell=True)
except subprocess.CalledProcessError as e:
print(e.output)
print('^Error Output^')
If I use the current command with the check_output command, I get an error stating that:
'"Write-Output 'Hello world'"' is not recognized as an internal or external command,
operable program or batch file.
If I just use the "dir" line, the script runs just fine. I'm at odds here as to why this would be happening. This is not the exact script that I'm running, but it produces the same problem on my machine. If I just type the problem command into the command line, it would output "Hello world" onto the new line just as expected.
Any insight as to why this would be happening would be greatly appreciated. If it's of relevance, I would like to not use any sort of admin privilege workaround.
I believe this is because in Windows your default Shell is not PowerShell, you could Execute a Powershell command, calling the executable by executing Powershell with the arguments you need.
For Example
POWERSHELL_COMMAND = r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe'
subprocess.Popen([POWERSHELL_COMMAND,
'-ExecutionPolicy', 'Unrestricted',
'Write-Output', 'Hello World'],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
if powershell is not in path you could use the full path for the executable
or if it's in path you could use just POWERSHELL_COMMAND = "powershell" as command, becareful, with the backslashed windows paths, to avoid errors you could use raw strings.
To verify that you have powershell in path, you could go to the configurations and check, or you could just open a cmd and type powershell and if It works, then you could assume that powershell is in path.
From the docs:
On Windows with shell=True, the COMSPEC environment variable specifies the default shell.
So set COMSPEC=powershell allows to make shell=True use powershell as default instead of cmd

Unable to run shell commands with * using python subprocess module

I am not able to run any commands using python subprocess module which contains * sign in the command.
I am using the call this way,
subprocess.Popen(
'cp /etc/varnida_sys/* /tmp/bucket/'.split(),
stdout=subprocess.PIPE).communicate()[0]
For this I am getting,
cp: cannot stat ‘/etc/varnida_sys/*’: No such file or directory
Why is this error coming, there is one file inside /etc/varnida_sys/genders
My investigations says that using regex like * needs some special handling. I am getting some errors in all those commands that contains *.
PS. I am not getting errors when I am running the same command through paramiko from remote host.
* is only understood by a shell (which expands it to a list of files), you need to pass shell=True to Popen(). Also, there's no need to split the command, you can use a string:
subprocess.Popen("cp /etc/varnida_sys/* /tmp/bucket/",
stdout=subprocess.PIPE, shell=True).communicate()[0]
As #triplee has suggested below, it's better to use some convenience wrapper for this task, e.g. subprocess.call():
subprocess.call("cp /etc/varnida_sys/* /tmp/bucket/", shell=True)

Running a PowerShell cmdlet in a Python script

I have a Python script and I want to run a PowerShell cmdlet. I've looked online and the only thing I can find is running a PowerShell script, but I feel like writing a cmdlet to a script and then dot sourcing it for execution would take a lot longer than needed.
I've tried using subprocess.Popen in the following way:
cmd = subprocess.Popen(['C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe', ps_cmdlet])
But ps_cmdlet is a python string variable with a powershell cmdlet as its value. So, I'm obviously getting a "No such file or directory" error. Is there any way to run a powershell cmdlet in a python script without using things like IronPython?
Thanks!
This works rather well
import subprocess
pl = subprocess.Popen(['powershell', 'get-process'], stdout=subprocess.PIPE).communicate()[0]
print(pl.decode('utf-8'))
Try the following (ps_cmdlet is a python string):
subprocess.call(ps_cmdlet)
edit: Here is an example that will output your machine's ip configuration to Powershell:
ps_cmdlet = 'ipconfig'
subprocess.call(ps_cmdlet)
another edit: Another way that works for me is:
ps_cmdlet = 'whatever command you would enter in powershell'
p = subprocess.Popen(ps_cmdlet,stdout=subprocess.PIPE)
p.communicate()
import subprocess
process = subprocess.Popen([r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe", "get-process"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
process_output = process.read().splitlines()
Above script would help in executing PS Cmdlets from Python.

Accessing matlab terminal from python

How do I call commands in a Matlab terminal when it's opened through Python? I call this:
subprocess.call(["matlab", "-nosplash", "-nodesktop", "-r"], shell=True)
which opens a terminal window. But how can I send new commands in there? I tried simply adding them to the current call, but they don't execute.
This worked for me:
subprocess.call(["matlab", "-nosplash", "-nodesktop", "-r", "command1;command2;"], shell=True, stdin=subprocess.PIPE, stout=subprocess.PIPE)

Categories