如何在Python脚本中请求UAC提升?

124 投票
12 回答
154568 浏览
提问于 2025-04-11 09:22

我想让我的Python脚本在Vista系统上复制文件。当我在普通的cmd.exe窗口运行它时,没有出现错误,但文件就是没有被复制。如果我以“管理员身份”运行cmd.exe,然后再运行我的脚本,那就没问题了。

这很正常,因为用户账户控制(UAC)通常会阻止很多文件系统的操作。

有没有办法让我在Python脚本中请求提升UAC权限(就是那些弹出窗口,提示“某个应用需要管理员权限,可以吗?”)

如果不行,我的脚本有没有办法检测到自己没有提升权限,这样就可以优雅地失败?

12 个回答

29

看起来你暂时无法提升应用程序的权限来完成某个特定任务。Windows在程序启动时就需要知道这个应用程序是否需要某些权限,并且在应用程序执行任何需要这些权限的任务时,会要求用户确认。要做到这一点,有两种方法:

  1. 写一个清单文件,告诉Windows这个应用程序可能需要一些权限。
  2. 通过另一个程序以提升的权限运行这个应用程序。

这两篇文章详细解释了这个过程是如何运作的。

如果你不想为CreateElevatedProcess API写一个复杂的ctypes封装,我建议使用Code Project文章中提到的ShellExecuteEx技巧(Pywin32自带了ShellExecute的封装)。怎么做呢?大概是这样的:

当你的程序启动时,它会检查自己是否有管理员权限,如果没有,就用ShellExecute技巧重新运行自己并立即退出;如果有权限,就执行当前的任务。

因为你把你的程序称作“脚本”,我想这对你来说已经足够了。

祝好。

73

我花了一些时间才让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)
153

截至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, " ".join(sys.argv), None, 1)

如果你使用的是Python 2.x,那么你需要把最后一行替换成:

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

另外,如果你把你的Python脚本转换成了可执行文件(使用像 py2execx_freezepyinstaller 这样的工具),那么在第四个参数中你应该使用 sys.argv[1:] 而不是 sys.argv

这里的一些优点包括:

  • 不需要额外的库。它只使用了标准库中的 ctypessys
  • 可以在Python 2和Python 3上都能运行。
  • 不需要修改文件资源,也不需要创建清单文件。
  • 如果你不在if/else语句下面添加代码,代码就不会被执行两次。
  • 你可以在最后一行获取API调用的返回值,并在失败时采取行动(返回值 <= 32)。可以在这里查看可能的返回值。
  • 你可以通过修改第六个参数来改变新进程的显示方式。

关于底层ShellExecute调用的文档可以在这里找到。

撰写回答