我想我Python脚本文件复制在Vista。当我运行它来自一个正常的 cmd.exe 窗口,没有错误而产生的,而该文件不会被复制。如果我运行 cmd.exe "作为管理员",然后运行我的剧本,它工作正常。

这是有道理的,因为用户账户控制(UAC)通常可防止许多文件系统的行动。

有没有办法我可以从内Python脚本,调用UAC提升的请求(这些对话是这样说:"这样的程序需要管理访问,是这样的好吗?")

如果这不可能,有没有办法我的剧本至少可以探测的,它没有升高,所以它可能会失败的优雅?

有帮助吗?

解决方案

作为2017年,一个简单的方法来实现这一目标如下:

import ctypes, sys

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

if is_admin():
    # Code of your program here
else:
    # Re-run the program with admin rights
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)

如果您使用的是蟒蛇2.x,然后应将最后一行:

ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

还注意到,如果转换你python脚本到一个可执行的文件(使用的工具喜欢 py2exe, cx_freeze, pyinstaller),那么你应该替代的第四个参数对于空string("").

其中的一些优点在这里是:

  • 没有外部图书馆所需的(也Python用于Windows的延伸)。它只能使用 ctypes 从标准图书馆。
  • 适用于这两蟒蛇2和Python3.
  • 没有必要修改文件的资源,也没有创建一个清单文件。
  • 如果不添加下面的代码如果/其他声明,该代码永远不会被执行的两倍。
  • 你可以很容易地修改它有一个特殊的行为如果用户拒绝UAC提示。
  • 你可以指定参数修改的第四个参数。
  • 你可以指定方法显示修改的第六次参数。

文件的基础ShellExecute呼叫 在这里,.

其他提示

我花了一点时间让dguaraglia的答案正常工作,所以为了节省他人的时间,这就是我为实现这个想法所做的:

import os
import sys
import win32com.shell.shell as shell
ASADMIN = 'asadmin'

if sys.argv[-1] != ASADMIN:
    script = os.path.abspath(sys.argv[0])
    params = ' '.join([script] + sys.argv[1:] + [ASADMIN])
    shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params)
    sys.exit(0)

似乎没有办法提升应用程序权限一段时间来执行特定任务。 Windows需要在程序开始时知道应用程序是否需要某些权限,并且会要求用户确认应用程序何时执行需要这些权限的任务。有两种方法可以做到这一点:

  1. 编写一个清单文件,告诉Windows应用程序可能需要一些权限
  2. 使用其他程序中的提升权限运行应用程序
  3. 两个 文章更详细地解释了它是如何工作的。

    如果您不想为CreateElevatedProcess API编写令人讨厌的ctypes包装器,我会做的是使用CodePro文章中解释的ShellExecuteEx技巧(Pywin32附带了ShellExecute的包装器)。怎么样?像这样:

    当你的程序启动时,会检查它是否具有管理员权限,如果它没有使用ShellExecute技巧自行运行并立即退出,如果有,则执行手头的任务。

    当您将程序描述为“脚本”时,我认为这足以满足您的需求。

    干杯。

多年前就认识到这个问题,我认为frmdstryr在 github 上提供了更优雅的解决方案使用他的模块pyminutils:

摘录:

import pythoncom
from win32com.shell import shell,shellcon

def copy(src,dst,flags=shellcon.FOF_NOCONFIRMATION):
    """ Copy files using the built in Windows File copy dialog

    Requires absolute paths. Does NOT create root destination folder if it doesn't exist.
    Overwrites and is recursive by default 
    @see http://msdn.microsoft.com/en-us/library/bb775799(v=vs.85).aspx for flags available
    """
    # @see IFileOperation
    pfo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation,None,pythoncom.CLSCTX_ALL,shell.IID_IFileOperation)

    # Respond with Yes to All for any dialog
    # @see http://msdn.microsoft.com/en-us/library/bb775799(v=vs.85).aspx
    pfo.SetOperationFlags(flags)

    # Set the destionation folder
    dst = shell.SHCreateItemFromParsingName(dst,None,shell.IID_IShellItem)

    if type(src) not in (tuple,list):
        src = (src,)

    for f in src:
        item = shell.SHCreateItemFromParsingName(f,None,shell.IID_IShellItem)
        pfo.CopyItem(item,dst) # Schedule an operation to be performed

    # @see http://msdn.microsoft.com/en-us/library/bb775780(v=vs.85).aspx
    success = pfo.PerformOperations()

    # @see sdn.microsoft.com/en-us/library/bb775769(v=vs.85).aspx
    aborted = pfo.GetAnyOperationsAborted()
    return success is None and not aborted    

这利用COM接口并自动指示熟悉的对话框提示需要管理员权限,如果您要复制到需要管理员权限的目录中,您将看到该提示,并在复制操作期间提供典型的文件进度对话框。

以下示例建立在 MARTIN DE LA FUENTE SAAVEDRA的出色的工作和接受的答案之上。特别是,引入了两个枚举。第一个允许轻松指定如何打开提升的程序,第二个允许在需要轻松识别错误时提供帮助。请注意,如果您希望将所有命令行参数传递给新进程,则 sys.argv [0] 应该替换为函数调用: subprocess.list2cmdline(sys.argv)

#! /usr/bin/env python3
import ctypes
import enum
import subprocess
import sys

# Reference:
# msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx


# noinspection SpellCheckingInspection
class SW(enum.IntEnum):
    HIDE = 0
    MAXIMIZE = 3
    MINIMIZE = 6
    RESTORE = 9
    SHOW = 5
    SHOWDEFAULT = 10
    SHOWMAXIMIZED = 3
    SHOWMINIMIZED = 2
    SHOWMINNOACTIVE = 7
    SHOWNA = 8
    SHOWNOACTIVATE = 4
    SHOWNORMAL = 1


class ERROR(enum.IntEnum):
    ZERO = 0
    FILE_NOT_FOUND = 2
    PATH_NOT_FOUND = 3
    BAD_FORMAT = 11
    ACCESS_DENIED = 5
    ASSOC_INCOMPLETE = 27
    DDE_BUSY = 30
    DDE_FAIL = 29
    DDE_TIMEOUT = 28
    DLL_NOT_FOUND = 32
    NO_ASSOC = 31
    OOM = 8
    SHARE = 26


def bootstrap():
    if ctypes.windll.shell32.IsUserAnAdmin():
        main()
    else:
       # noinspection SpellCheckingInspection
        hinstance = ctypes.windll.shell32.ShellExecuteW(
            None,
            'runas',
            sys.executable,
            subprocess.list2cmdline(sys.argv),
            None,
            SW.SHOWNORMAL
        )
        if hinstance <= 32:
            raise RuntimeError(ERROR(hinstance))


def main():
    # Your Code Here
    print(input('Echo: '))


if __name__ == '__main__':
    bootstrap()

这可能无法完全回答您的问题,但您也可以尝试使用Elevate Command Powertoy以使用提升的UAC权限运行脚本。

http://technet.microsoft.com/en-us/杂志/ 2008.06.elevation.aspx

我认为如果你使用它,它看起来就像'提升python yourscript.py'

如果您的脚本始终需要管理员权限,那么:

runas /user:Administrator "python your_script.py"

您可以在某处创建快捷方式并作为目标使用: python yourscript.py 然后在属性和高级选择下以管理员身份运行。

当用户执行快捷方式时,它会要求他们提升应用程序。

Jorenko上述工作的变体允许提升的进程使用相同的控制台(但请参阅下面的评论):

def spawn_as_administrator():
    """ Spawn ourself with administrator rights and wait for new process to exit
        Make the new process use the same console as the old one.
          Raise Exception() if we could not get a handle for the new re-run the process
          Raise pywintypes.error() if we could not re-spawn
        Return the exit code of the new process,
          or return None if already running the second admin process. """
    #pylint: disable=no-name-in-module,import-error
    import win32event, win32api, win32process
    import win32com.shell.shell as shell
    if '--admin' in sys.argv:
        return None
    script = os.path.abspath(sys.argv[0])
    params = ' '.join([script] + sys.argv[1:] + ['--admin'])
    SEE_MASK_NO_CONSOLE = 0x00008000
    SEE_MASK_NOCLOSE_PROCESS = 0x00000040
    process = shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params, fMask=SEE_MASK_NO_CONSOLE|SEE_MASK_NOCLOSE_PROCESS)
    hProcess = process['hProcess']
    if not hProcess:
        raise Exception("Could not identify administrator process to install drivers")
    # It is necessary to wait for the elevated process or else
    #  stdin lines are shared between 2 processes: they get one line each
    INFINITE = -1
    win32event.WaitForSingleObject(hProcess, INFINITE)
    exitcode = win32process.GetExitCodeProcess(hProcess)
    win32api.CloseHandle(hProcess)
    return exitcode

这主要是对Jorenko的答案的升级,它允许在Windows中使用带空格的参数,但在Linux上也应该运行得很好:) 此外,将使用cx_freeze或py2exe,因为我们不使用 __ file __ ,但 sys.argv [0] 作为可执行文件

import sys,ctypes,platform

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        raise False

if __name__ == '__main__':

    if platform.system() == "Windows":
        if is_admin():
            main(sys.argv[1:])
        else:
            # Re-run the program with admin rights, don't use __file__ since py2exe won't know about it
            # Use sys.argv[0] as script path and sys.argv[1:] as arguments, join them as lpstr, quoting each parameter or spaces will divide parameters
            lpParameters = ""
            # Litteraly quote all parameters which get unquoted when passed to python
            for i, item in enumerate(sys.argv[0:]):
                lpParameters += '"' + item + '" '
            try:
                ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, lpParameters , None, 1)
            except:
                sys.exit(1)
    else:
        main(sys.argv[1:])
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top