This code attempts to implement psexec in python code, using wmi. As part of a project of mine I had to run remote commands on remote Windows machines from other Windows machine. At first I used psexec for that with subprocess.Popen. The reason in this code for creating .bat files and running them remotely is because complicated commands do not run properly with Win32_Process.Create
In this code I used this code: http://code.activestate.com/recipes/442521/history/3/
required installations:
pywin32 - http://sourceforge.net/projects/pywin32/files/pywin32/Build216/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | #! /usr/bin/python
__author__="ofer.helman"
__date__ ="$Nov 9, 2011 9:30:26 PM$"
import os
import wmi
import shutil
import win32wnet
REMOTE_PATH = 'c:\\'
def main():
ip = 'or_hostname'
username = 'user'
password = 'pass'
server = WindowsMachine(ip, username, password)
print server.run_remote('ipconfig', async=False, output=True)
def create_file(filename, file_text):
f = open(filename, "w")
f.write(file_text)
f.close()
class WindowsMachine:
def __init__(self, ip, username, password, remote_path=REMOTE_PATH):
self.ip = ip
self.username = username
self.password = password
self.remote_path = remote_path
try:
print "Establishing connection to %s" %self.ip
self.connection = wmi.WMI(self.ip, user=self.username, password=self.password)
print "Connection established"
except wmi.x_wmi:
print "Could not connect to machine"
raise
def run_remote(self, cmd, async=False, minimized=True, output=False):
"""
this function runs cmd on remote machine, using wmi. the function create a .bat file,
copies it to the remote machine, and runs the .bat file
inputs: cmd - command to run
async - False, waits for command to finish, True, return immidiatly
mimimized - window state
output - True, returns the command's output
output: return value of the command
output of the command if true
"""
output_data = None
pwd = os.getcwd()
bat_local_path = os.path.join(pwd, 'output.bat')
bat_remote_path = os.path.join(self.remote_path, 'output.bat')
output_remote_path = os.path.join(self.remote_path, 'output.out')
output_local_path = os.path.join(pwd, 'output.out')
text = cmd + " > " + output_remote_path
create_file(bat_local_path, text)
self.net_copy(bat_local_path, self.remote_path)
batcmd = bat_remote_path
SW_SHOWMINIMIZED = 0
if not minimized:
SW_SHOWMINIMIZED = 1
print "Executing %s" %cmd
startup = self.connection.Win32_ProcessStartup.new (ShowWindow=SW_SHOWMINIMIZED)
process_id, return_value = self.connection.Win32_Process.Create (CommandLine=batcmd, ProcessStartupInformation=startup)
if async:
watcher = self.connection.watch_for (
notification_type="Deletion",
wmi_class="Win32_Process",
delay_secs=1,
)
watcher ()
if output and not async:
print 'copying back ' + output_remote_path
self.net_copy_back(output_remote_path, output_local_path)
output_data = open(output_local_path, 'r')
output_data = "".join(output_data.readlines())
self.net_delete(output_remote_path)
self.net_delete(bat_remote_path)
return return_value, output_data
def net_copy(self, source, dest_dir, move=False):
""" Copies files or directories to a remote computer. """
print "Start copying files to " + self.ip
if self.username == '':
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
else:
# Create a directory anyway if file exists so as to raise an error.
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
shutil.copy(source, dest_dir)
else:
self._wnet_connect()
dest_dir = self._covert_unc(dest_dir)
# Pad a backslash to the destination directory if not provided.
if not dest_dir[len(dest_dir) - 1] == '\\':
dest_dir = ''.join([dest_dir, '\\'])
# Create the destination dir if its not there.
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
else:
# Create a directory anyway if file exists so as to raise an error.
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
if move:
shutil.move(source, dest_dir)
else:
shutil.copy(source, dest_dir)
def net_copy_back(self, source_file, dest_file):
""" Copies files or directories to a remote computer. """
print "Start copying files " + source_file + " back from " + self.ip
if self.username == '':
shutil.copy(source_file, dest_file)
else:
self._wnet_connect()
source_unc = self._covert_unc(source_file)
shutil.copyfile(source_unc, dest_file)
def _wnet_connect(self):
unc = ''.join(['\\\\', self.ip])
try:
win32wnet.WNetAddConnection2(0, None, unc, None, self.username, self.password)
except Exception, err:
if isinstance(err, win32wnet.error):
# Disconnect previous connections if detected, and reconnect.
if err[0] == 1219:
win32wnet.WNetCancelConnection2(unc, 0, 0)
return self._wnet_connect(self)
raise err
def _covert_unc(self, path):
""" Convert a file path on a host to a UNC path."""
return ''.join(['\\\\', self.ip, '\\', path.replace(':', '$')])
def copy_folder(self, local_source_folder, remote_dest_folder):
files_to_copy = os.listdir(local_source_folder)
for file in files_to_copy:
file_path = os.path.join(local_source_folder, file)
print "Copying " + file
try:
self.net_copy(file_path, remote_dest_folder)
except WindowsError:
print 'could not connect to ', self.ip
except IOError:
print 'One of the files is being used on ', self.ip, ', skipping the copy procedure'
def net_delete(self, path):
""" Deletes files or directories on a remote computer. """
if self.username == '':
os.remove(path)
else:
self._wnet_connect()
path = self._covert_unc(path)
if os.path.exists(path):
# Delete directory tree if object is a directory.
if os.path.isfile(path):
os.remove(path)
else:
shutil.rmtree(path)
else:
# Remove anyway if non-existent so as to raise an error.
os.remove(path)
if __name__ == "__main__":
main()
|
I know that this is a stupid question but is this code used to create python executables?
No, it is only used to execute commands on a remote windows host. This code is not trying to do what py2exe does.
The code doesn't work as expected on entire directory tree. All I am trying to do is copy an entire directory structure from a windows machine to remote windows machine. I changed copy commands to copytree but got an error saying "could no connect to ipaddress". But works very well on files inside a directory. My requirement is to recursively copy directories and files under a directory. Any help is appreciated. Thanks
I couldn't wait. Found a way out. Just zipped the entire directory and moved it to the remote machine with your code:)
Here you can find a python psexec:
https://code.google.com/p/impacket/source/browse/trunk/examples/psexec.py
you have to check out Impacket trunk
I can see from the code that async=True is waiting for command to finish while async=False is not. Is that right? (I also tried executing your script, it works without a problem, jsut that it was not waiting for the output.txt to be created on remote machine for 'dir' command as it needed to be with async=False)
Gaurav, did you run it with output=True ?
I have a exe in remote machine when I try to execute this code My exe file is not getting executed, where as 'ipconfig' and other system commands are working fine.Please help...
sdv, sometimes I use batch file to try and understand these type of problems
my_exe.bat:
Hello. I had the same problems related by Gaurav and sdv.
In my case I had to put the exe program which I wanted to run in the remote computer in a folder in the PATH of this computer. To simply put the exe in REMOTE_PATH folder was not enough. Seems to me that it could be avoided by instructing the service to use REMOTE_PATH as working directory.
When the code reaches Win32_Process. Create it immediately returns a return_value. This might happen because the batch file created above does not wait for the command it calls. I am still trying to figure out how to avoid this, but I am wondering: are you still using this code and if you are, do you have it written in python 3?
Connection is not successful in case of Multithreading.
I'm getting the following error -
<x_wmi: Unexpected COM Error (-2147352567, 'Exception occurred.', (0, u'SWbemLocator', u'The RPC server is unavailable. ', None, 0, -2147023174), None)>
Felipe, I see what confused you, and I think you are right. REMOTE_PATH is only where the output is saved, for the command you should supply the full path. I might consider to change it to how you thought it should work
Hemant, I don't think it has something to do with multithreading, seems like either you have the wrong ip/pass/user or your remote computer is down
Let me know in what line your code fails.
try to run this in python shell:
After connecting iam not able to get the option self.connection.Win32_ProcessStartup. how ca i get the wn32_process. i installed the pywin32. could you please help me?
Hey All,
I just modified the above code for my requirement as:
" I have a windows server. I just want to copy some files on that remote machine to my local machine"
But the below code fails at "Connection Fail!" because the WNetAddConnection2() returns None.
Can you Please see what's wrong here:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
import os import wmi import shutil import win32wnet
def _wnet_connect(): try:
_wnet_connect() shutil.copyfile("\\my_windowsserver\e$\myfiles\", "D:\")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////