Welcome, guest | Sign In | My Account | Store | Cart

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/

wmi - http://timgolden.me.uk/python/downloads/

Python, 178 lines
  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()

16 comments

Alexander James Wallar 12 years, 4 months ago  # | flag

I know that this is a stupid question but is this code used to create python executables?

Ofer Helman (author) 12 years, 4 months ago  # | flag

No, it is only used to execute commands on a remote windows host. This code is not trying to do what py2exe does.

Suprith 12 years, 4 months ago  # | flag

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

Suprith 12 years, 4 months ago  # | flag

I couldn't wait. Found a way out. Just zipped the entire directory and moved it to the remote machine with your code:)

beto 11 years, 8 months ago  # | flag

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

Gaurav Halbe 10 years, 9 months ago  # | flag

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)

Ofer Helman (author) 10 years, 8 months ago  # | flag

Gaurav, did you run it with output=True ?

sdv 10 years, 6 months ago  # | flag

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...

Ofer Helman (author) 10 years, 6 months ago  # | flag

sdv, sometimes I use batch file to try and understand these type of problems

my_exe.bat:

echo 'start'
my_exe.exe > c:\debug.log
echo 'end'
Felipe Araujo 10 years, 5 months ago  # | flag

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?

Hemant Rajput 10 years, 4 months ago  # | flag

Connection is not successful in case of Multithreading.

Hemant Rajput 10 years, 4 months ago  # | flag

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)>

Ofer Helman (author) 10 years, 4 months ago  # | flag

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

Ofer Helman (author) 10 years, 4 months ago  # | flag

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:

import wmi
wmi.WMI(ip, user=username, password=password)
kiran 9 years, 8 months ago  # | flag

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?

prem 9 years, 1 month ago  # | flag

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:

    if(win32wnet.WNetAddConnection2(0, None,"\\\\my_windowsserver", None, "my_username", "my_password")):
        print ("Connection Successful!")
    else:
        print("Connection Fail!")

_wnet_connect() shutil.copyfile("\\my_windowsserver\e$\myfiles\", "D:\")

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////