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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4273939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:40:01  来源:igfitidea点击:

Python subprocess.Popen as different user on Windows

pythonwindowssubprocessrunas

提问by Eric Pruitt

What is the best manner of launching a subprocess as a different user in Python on Windows? Preferably XP and up, but if it works only on Vista and 7, I can live with that too.

在 Windows 上的 Python 中以不同用户身份启动子进程的最佳方式是什么?最好是 XP 及更高版本,但如果它仅适用于 Vista 和 7,我也可以接受。

采纳答案by DaveP

I am not sure if you can do this with the standard python libraries. However, the pywin32package has a win32process.CreateProcessAsUserfunction which may be what you need.

我不确定你是否可以用标准的 python 库来做到这一点。但是,pywin32包有一个win32process.CreateProcessAsUser函数,这可能正是您所需要的。

回答by khachik

Another option is to popen not the desired process but runas ...command. Note that the Run Asservice should be enabled and running.

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

回答by Steinar Lima

I ended up augmenting subprocess:

我最终增加了子流程:

#!/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

The following code launches cmd.exeas user username:

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

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