Python subprocess.Popen作为Windows上的不同用户

时间:2010-11-25 05:12:58

标签: python windows subprocess runas

在Windows上以Python的形式启动子进程作为不同用户的最佳方式是什么?最好是XP及以上,但如果它仅适用于Vista和7,我也可以忍受。

3 个答案:

答案 0 :(得分:5)

我不确定您是否可以使用标准python库执行此操作。但是,pywin32包具有win32process.CreateProcessAsUser功能,可能就是您所需要的。

答案 1 :(得分:2)

另一个选择是不是所需的进程而是runas ...命令。请注意,应启用并运行Run As服务。

答案 2 :(得分:2)

我最终增加了子流程:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import subprocess
import win32con
import win32process
import win32security

from subprocess import *

__all__ = ["Popen","PIPE", "STDOUT", "call", "check_call",
    "CalledProcessError", "CREATE_NEW_CONSOLE", "LoginSTARTUPINFO",
    "STARTUPINFO"]

class LoginSTARTUPINFO(object):
    """
    Special STARTUPINFO instance that carries login credentials. When a
    LoginSTARTUPINFO instance is used with Popen, the process will be executed
    with the credentials used to instantiate the class.

    If an existing vanilla STARTUPINFO instance needs to be converted, it
    can be supplied as the last parameter when instantiating LoginSTARTUPINFO.

    The LoginSTARTUPINFO cannot be used with the regular subprocess module.

    >>> import subprocesswin32 as subprocess
    >>> sysuser = LoginSTARTUPINFO("username", "pswd123", "machine")
    >>> stdout, stderr = subprocess.Popen("cmd.exe", stdout=subprocess.PIPE,
    ...     startupinfo=sysuser).communicate()
    """
    def __init__(self, username, domain, password, startupinfo=None):
        m_startupinfo = win32process.STARTUPINFO()

        # Creates an actual win32 STARTUPINFO class using the attributes
        # of whatever STARTUPINFO-like object we are passed.
        for attr in dir(startupinfo):
            if not(attr.startswith("_") or attr not in dir(m_startupinfo)):
                setattr(m_startupinfo, attr, getattr(startupinfo, attr))

        # Login credentials
        self.credentials = (username, domain, password)
        # Proper win32 STARTUPINFO representation for CreateProcess
        self.win32startupinfo = m_startupinfo

def CreateProcess(*args):
    startupinfo = args[-1]

    # If we are passed a LoginSTARTUPINFO, that means we need to use
    # CreateProcessAsUser instead of the CreateProcess in subprocess
    if isinstance(startupinfo, LoginSTARTUPINFO):
        # Gets the actual win32 STARTUPINFO object from LoginSTARTUPINFO
        win32startupinfo = startupinfo.win32startupinfo

        mkprocargs = args[:-1] + (win32startupinfo,)

        login, domain, password = startupinfo.credentials

        # Get a user handle from the credentials
        userhandle = win32security.LogonUser(login, domain, password,
            win32con.LOGON32_LOGON_INTERACTIVE,
            win32con.LOGON32_PROVIDER_DEFAULT)

        try:
            # Return the pipes from CreateProcessAsUser
            return win32process.CreateProcessAsUser(userhandle, *mkprocargs)
        finally:
            # Close the userhandle before throwing whatever error arises
            userhandle.Close()

    return win32process.CreateProcess(*args)

# Overrides the CreateProcess module of subprocess with ours. CreateProcess
# will automatically act like the original CreateProcess when it is not passed
# a LoginSTARTUPINFO object.
STARTUPINFO = subprocess.STARTUPINFO = win32process.STARTUPINFO
subprocess._subprocess.CreateProcess = CreateProcess

以下代码以用户cmd.exe启动username

>>> import subprocesswin32 as subprocess
>>> sysuser = LoginSTARTUPINFO("username", "pswd123", "machine")
>>> stdout, stderr = subprocess.Popen("cmd.exe", stdout=subprocess.PIPE,
...     startupinfo=sysuser).communicate()