如何在Python脚本中请求UAC提升?
我想让我的Python脚本在Vista系统上复制文件。当我在普通的cmd.exe
窗口运行它时,没有出现错误,但文件就是没有被复制。如果我以“管理员身份”运行cmd.exe
,然后再运行我的脚本,那就没问题了。
这很正常,因为用户账户控制(UAC)通常会阻止很多文件系统的操作。
有没有办法让我在Python脚本中请求提升UAC权限(就是那些弹出窗口,提示“某个应用需要管理员权限,可以吗?”)
如果不行,我的脚本有没有办法检测到自己没有提升权限,这样就可以优雅地失败?
12 个回答
看起来你暂时无法提升应用程序的权限来完成某个特定任务。Windows在程序启动时就需要知道这个应用程序是否需要某些权限,并且在应用程序执行任何需要这些权限的任务时,会要求用户确认。要做到这一点,有两种方法:
- 写一个清单文件,告诉Windows这个应用程序可能需要一些权限。
- 通过另一个程序以提升的权限运行这个应用程序。
这两篇文章详细解释了这个过程是如何运作的。
如果你不想为CreateElevatedProcess API写一个复杂的ctypes封装,我建议使用Code Project文章中提到的ShellExecuteEx技巧(Pywin32自带了ShellExecute的封装)。怎么做呢?大概是这样的:
当你的程序启动时,它会检查自己是否有管理员权限,如果没有,就用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)
截至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脚本转换成了可执行文件(使用像 py2exe
、cx_freeze
、pyinstaller
这样的工具),那么在第四个参数中你应该使用 sys.argv[1:]
而不是 sys.argv
。
这里的一些优点包括:
- 不需要额外的库。它只使用了标准库中的
ctypes
和sys
。 - 可以在Python 2和Python 3上都能运行。
- 不需要修改文件资源,也不需要创建清单文件。
- 如果你不在if/else语句下面添加代码,代码就不会被执行两次。
- 你可以在最后一行获取API调用的返回值,并在失败时采取行动(返回值 <= 32)。可以在这里查看可能的返回值。
- 你可以通过修改第六个参数来改变新进程的显示方式。
关于底层ShellExecute调用的文档可以在这里找到。