Python Popen hanging with psexec - undesired results - python

I'm having an issue with subprocess.Popen and what I believe to be pipes. I have the following block of code which works without issue 100% of the time when running from the cli:
p = subprocess.Popen("psexec \\\\" + serverName.get() + " cmd /c \
ver & \
echo %USERDOMAIN% & \
dir /a C:\pagefile.sys | find \"pagefile.sys\" & \
dir C:\ | find \"bytes free\" & \
dir D:\ | find \"bytes free\" ", \
stdin=None, stdout=subprocess.PIPE, stderr=None)
### Assign the results from the Popen
results = p.communicate()[0]
rc = p.returncode
print 'results: ' + str(results)
sys.exit()
Output:
PsExec v1.90 - Execute processes remotely
Copyright (C) 2001-2007 Mark Russinovich
Sysinternals - www.sysinternals.com
The device is not ready.
cmd exited on XXXXXXX with error code 1.
Microsoft Windows XP [Version 5.1.2600]
PROD
02/23/2011 09:37 AM 1,610,612,736 pagefile.sys
49 Dir(s) 17,104,437,248 bytes free
I had this program complete, but once I compiled it with py2exe, it would just hang or crash. I tracked that issue down to py2exe not liking undefined stdin, out, or err in subprocess. I then modified my code as follows:
p = subprocess.Popen("psexec \\\\" + serverName.get() + " cmd /c \
ver & \
echo %USERDOMAIN% & \
dir /a C:\pagefile.sys | find \"pagefile.sys\" & \
dir C:\ | find \"bytes free\" & \
dir D:\ | find \"bytes free\" ", \
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.stdin.close()
### Assign the results from the Popen
results = p.communicate()[0]
rc = p.returncode
print 'results: ' + str(results)
sys.exit()
This code works 100% of the time as well, but when I print results, it only shows me the standard psexec messages, not the output of the commands executed.
Output:
results:
PsExec v1.90 - Execute processes remotely
Copyright (C) 2001-2007 Mark Russinovich
Sysinternals - www.sysinternals.com
cmd exited on XXXXXXX with error code 1.
I tried to combat this by adding shell=true to the subprocess options, but when I do that the program just hangs 99% of the time. It will actually run 1% of the time . I noticed that while the program is hanging, if I go into task manager and manually kill the psexec process, the desired output is shown. This is driving me crazy and I've been searching forever without finding anything. The code is running on WinXP python v2.7. Please let me know if you have any questions or need any additional information.
Hanging Code:
p = subprocess.Popen("psexec \\\\" + serverName.get() + " cmd /c \
ver & \
echo %USERDOMAIN% & \
dir /a C:\pagefile.sys | find \"pagefile.sys\" & \
dir C:\ | find \"bytes free\" & \
dir D:\ | find \"bytes free\" ", \
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
p.stdin.close()
### Assign the results from the Popen
results = p.communicate()[0]
rc = p.returncode
print 'results:' + str(results)
sys.exit()
Desired output after killing psexec.exe from task manager:
results:
PsExec v1.90 - Execute processes remotely
Copyright (C) 2001-2007 Mark Russinovich
Sysinternals - www.sysinternals.com
PROD
02/23/2011 09:37 AM 1,610,612,736 pagefile.sys
49 Dir(s) 17,102,487,552 bytes free
The device is not ready.

[This should be a comment, but I don't have the rep to leave comments]
I've heard of a lot of problems with subprocess.PIPE. Try making stdin, stdout, and stderr all point to temporary files. Then you can use p.wait() instead of communicate(). Does that seem to work correctly?

I've seen this problem a once:
Redirecting traffic to temporary files seems a working solution - the problem is the additional code needed to access the process output - but it is a stable solution. The problem is the additional code needed to get to the process output (if you want to display it while it is running - if not, it's just dumping a file)
You could also check fabric's local implementations - I haven't run psexec with it, but all other processes worked fine (except for the fact it does not provide a timeout mechanism)

try running the psexec with -i
it works for me
p = subprocess.Popen("psexec " "-i " . . .

Related

run multiple shell command that depend on the first one (dir_path)

I'm trying to use subprocess.run to build my CMake project but the code finishing without errors but its not working.
the code is:
import subprocess
git_repo_remvoe_destination = '/home/yaodav/Desktop/'
git_repo_clone_destination = git_repo_remvoe_destination + 'test_clone_git'
test_path = git_repo_clone_destination + "/test/"
cmake_debug_path = test_path + "cmake-debug-build"
cmake_build_command = " cmake -Bcmake-build-debug -H. -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/local/bin/gcc " \
"-DCMAKE_CXX_COMPILER=/usr/local/bin/c++ -Bcmake-build-debug -H. " \
"-DSYTEM_ARCH=x86_64-pc-linux-gnu-gcc-7.4.0"
cmake_link_command = "cmake --build cmake-build-debug --target all"
cmake_command = ['cd '+test_path, cmake_build_command, cmake_link_command]
out = subprocess.run(cmake_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
I tried this answer but it didn't work
how to I do that?
2 Issues.
First you should call subprocess.run() once for each command instead of putting three different commands in a list.
Second: The cd ... command just changes the present working directory in one sub process and the consecutive command will not be any more in the same directory.
However there is a simple solution to it.
subprocess.run has a cwd parameter ( https://docs.python.org/2/library/subprocess.html#popen-constructor ) that allows you to specify the directory in which a subprocess should be executed.
So Following should do:
out = subprocess.run(cmake_build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=test_path, shell=True)
out += subprocess.run(cmake_link_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=test_path, shell=True)

The term 'Select-String' is not recognized

I am trying to get only the PID by running this python script.
My current error:
Select string is not recognized as an internal or external command
To deal with this error, I thought that I needed to escape | by adding ^ --> But apparently it doesn't work
I added in some \ to escape ", hopefully it's correct?
cmd = "netstat -ano | findstr " + str(o)
print (cmd)
cmd += " | Select-String \"TCP\s+(.+)\:(.+)\s+(.+)\:(\d+)\s+(\w+)\s+(\d+)\" | ForEach-Object { Write-Output $_.matches[0].Groups[6].value }"
print (cmd)
pid = run_command(cmd)
The run_command method does this:
def run_command(cmd_array,os_name='posix'):
p = subprocess.Popen(cmd_array,shell=True,cwd=os.getcwd())
output,err = p.communicate()
print('output=%s'%output)
print('err=%s'%err)
return output
Expected Result
When I run solely the command in command prompt, it gives me the PID --> which is 7556 in this case.
Not too sure why it is not working for the script but working in command prompt by itself.
This question is specific to windows OS
Answer to my own question
With help from the comments, i did not use my run_command method since it was using shell = True.
shell = True refers to cmd.exe on Windows, not powershell.
The commands i have written are powershell commands.
Directly use subprocess.call to run powershell commands
Python scripts
cmd = "netstat -ano | findstr 8080"
cmd += " | Select-String \"TCP\s+(.+)\:(.+)\s+(.+)\:(\d+)\s+(\w+)\s+(\d+)\" | ForEach-Object { Write-Output $_.matches[0].Groups[6].value }"
subprocess.call(["powershell.exe", cmd])
#this does the job but the code will print extra zeros along with PID. It was not what i was looking for.
Result:
6492 (Prints out the PID Along with some additional zeros)
What worked for me - For those who are trying to get only PID and kill port using PID in python script
cmd = "for /f \"tokens=5\" %a in ('netstat -aon ^| find \":8080"
cmd += "\" ^| find \"LISTENING\"\') do taskkill /f /pid %a"
#I added in some \ to escape the "
run_command(cmd)
Result:
SUCCESS: The process with PID 2072 has been terminated

How to execute awk command inside python

I am trying to run the following awk command inside python but I get a syntax error related to the quotes:
import subprocess
COMMAND = "df /dev/sda1 | awk /'NR==2 {sub("%","",$5); if ($5 >= 80) {printf "Warning! Space usage is %d%%", $5}}"
subprocess.call(COMMAND, shell=True)
I tried to escape the quotes but I am still getting the same error.
You may want to put ''' or """ around the string since you have both ' and ".
import subprocess
COMMAND = '''"df /dev/sda1 | awk /'NR==2 {sub("%","",$5); if ($5 >= 80) {printf "Warning! Space usage is %d%%", $5}}"'''
subprocess.call(COMMAND, shell=True)
There also seems to be a relevant answer already for this as well: awk commands within python script
Try this:
import subprocess
COMMAND="df /dev/sda1 | awk 'NR==2 {sub(\"%\",\"\",$5); if ($5 >= 80) {printf \"Warning! Space usage is %d%%\", $5}}'"
subprocess.Popen(COMMAND,stdin=subprocess.PIPE,stdout=subprocess.PIPE, shell=True).stdout.read()
I was writing a python script for my deployment purpose and one part of the script was to explicitely kill the process if its not stopped successfully.
Below is the python code which actually performs
Find the processId of the process named myApplication
ps -ef | grep myApplication | grep -v grep | awk {'print $2'}
and then perform
kill -9 PID //where PID is output of earlier command
import subprocess
import signal
def killApplicationProcessIfStillRunning(app_name):
p1 = subprocess.Popen(['ps', '-ef'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', app_name],stdin=p1.stdout, stdout=subprocess.PIPE)
p3 = subprocess.Popen(['grep', '-v' , 'grep'],stdin=p2.stdout, stdout=subprocess.PIPE)
p4 = subprocess.Popen(['awk', '{print $2}'],stdin=p3.stdout, stdout=subprocess.PIPE)
out, err = p4.communicate()
if out:
print 'Attempting to kill '+app_name +' process with PID ' +out.splitlines()[0]
os.kill(int(out.splitlines()[0]),signal.SIGKILL)
Now invoke the above method as
killApplicationProcessIfStillRunning(myApplication)
Hope it helps someone.

Subprocess return code different than "echo $?"

I'm using subprocess to call a bash command in Python, and I'm getting a different return code than what the shell shows me.
import subprocess
def check_code(cmd):
print "received command '%s'" % (cmd)
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()
print "p.returncode is '%d'" % (p.returncode)
exit()
if p.returncode == 0:
return True
else:
return False
#End if there was a return code at all
#End get_code()
When sent "ls /dev/dsk &> /dev/null", check_code returns 0, but "echo $?" produces "2" in the terminal:
Welcome to Dana version 0.7
Now there is Dana AND ZOL
received command 'ls /dev/dsk &> /dev/null'
p.returncode is '0'
root#Ubuntu-14:~# ls /dev/dsk &> /dev/null
root#Ubuntu-14:~# echo $?
2
root#Ubuntu-14:~#
Does anyone know what's going on here?
According to subprocess.Popen, the shell used in your Python script is sh. This shell is the POSIX standard, as opposed to Bash, which has several nonstandard features such as the shorthand redirection &> /dev/null. sh, the Bourne shell, interprets this symbol as "run me in the background, and redirect stdout to /dev/null".
Since your subprocess.Popen opens a sh which runs ls in its own background, the return value of sh is used instead of ls, which in this case is 0.
If you want Bash behavior with your Python, I believe you may have to reconfigure (possibly recompile) Python itself. It's simpler to just use the sh syntax, which is ls /dev/dsk 2> /dev/null.
Following the suggestion by xi_, I split the command up in to space delineated fields, and it failed to run with "&>" and "/dev/null". I removed them, and it worked.
Then I put the command all back together to test it without "&> /dev/null", and that worked too. It appears that the addition of "&> /dev/null" throws subprocess off, somehow.
Welcome to Dana version 0.7
Now there is Dana AND ZOL
received command 'cat /etc/fstab'
p.wait() is 0
p.returncode is '0'
received command 'cat /etc/fstabb'
p.wait() is 1
p.returncode is '1'
received command 'cat /etc/fstab &> /dev/null'
p.wait() is 0
p.returncode is '0'
received command 'cat /etc/fstabb &> /dev/null'
p.wait() is 0
p.returncode is '0'
root#Ubuntu-14:~# cat /etc/fstab &> /dev/null
root#Ubuntu-14:~# echo $?
0
root#Ubuntu-14:~# cat /etc/fstabb &> /dev/null
root#Ubuntu-14:~# echo $?
1
root#Ubuntu-14:~#
I originally added the "&> /dev/null" to the call because I was seeing output on the screen from STDERR. Once I added stderr=PIPE to the subprocess call, that went away. I was just trying to silently check the code on the output behind the scenes.
If someone can explain why adding "&> /dev/null" to a subprocess call in Python causes it to behave unexpectedly, I'd be happy to select that as the answer!
You are using it as subprocess.Popen(cmd, shell=True), with cmd as string.
That means that subprocess will call under the hood /bin/sh with arguments. So you are getting back exit code of your shell.
If you need actually exit code of your command, split it into list and use shell=False.
subprocess.Popen(['cmd', 'arg1'], shell=False)

run Python file with root permission via php

I'm trying to run Python file with root access with php index
in php there is :
passthru('python /home/register/register.py '. $_POST['username'] . ' example.com ' . $_POST['password'] . ' ' . $_POST['email'] . ' ' . $ip . ' 1 2>&1');
and in Python file there is:
os.popen("sudo -u root -p password /sbin/ejabberdctl register %s %s %s" % (user,domain,password)).read()
is there any command with Python to login with root user then do command like : ls or mkdir
thnx.
from subprocess import PIPE,Popen
p = Popen(["sudo", "-s", "-S"], stdin=PIPE, stdout=PIPE, universal_newlines=True)
p.stdin.write("password\n")
p.stdin.write("mkdir foo\n")
p.stdin.write("id -u")
To see output use communicate:
from subprocess import PIPE,Popen
p = Popen(["sudo", "-s", "-S"], stdin=PIPE, stdout=PIPE, universal_newlines=True)
p.stdin.write("password\n")
p.stdin.write("ls -la\n")
p.stdin.write("/usr/bin/pip list\n")
p.stdin.write("id -u")
print(p.communicate()[0])
But be very sure you know what commands you are running.
I recently published a project that allows PHP to obtain and interact with a real Bash shell (as user: apache/www-data or root if needed). Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
//Setting the second argument in getShell():
//true will return a shell with root
//false will return a shell with the php execution user
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd("mkdir -p /some/path");
$return2 = $shell->exeCmd("ls --color=none /some/path");
notice the ls command has a switch called --color=none, that is needed because the bash shell will return color information as odd chars, the switch prevents it.

Categories