python程序,实现以管理员方式运行程序,也就是提升程序权限 |
您所在的位置:网站首页 › 以管理员身份运行cmdexe › python程序,实现以管理员方式运行程序,也就是提升程序权限 |
我希望我的Python脚本能够在Vista上复制文件。 当我从普通的cmd.exe窗口运行它时,不会生成错误,但不会复制文件。 如果我运行cmd.exe"作为管理员"然后运行我的脚本,它工作正常。 这是有道理的,因为用户帐户控制(UAC)通常会阻止许多文件系统操作。 有没有办法可以在Python脚本中调用UAC提升请求(这些对话框说"像这样的应用程序需要管理员访问权限,这样可以吗?") 如果那是不可能的,那么我的脚本是否有一种方法可以至少检测到它没有被提升以便它可以优雅地失败? 相关讨论stackoverflow.com/a/1445547/1628132在这个答案之后你使用py2exe从.py脚本创建一个.exe并使用一个名为'uac_info'的标志它是非常简洁的解决方案
截至2017年,实现这一目标的简单方法如下: 12345678910111213 import ctypes, sysdef is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False if is_admin(): # Code of your program hereelse: # Re-run the program with admin rights ctypes.windll.shell32.ShellExecuteW(None,"runas", sys.executable, __file__, None, 1) 如果您使用的是Python 2.x,那么您应该替换最后一行: 1 ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)另请注意,如果您将python脚本转换为可执行文件(使用py2exe,cx_freeze,pyinstaller等工具),则应将第四个参数替换为空字符串("")。 这里的一些优点是: 不需要外部库(也不是用于Windows扩展的Python)。它仅使用标准库中的ctypes。 适用于Python 2和Python 3。 无需修改文件资源也无需创建清单文件。 如果你没有在if / else语句下面添加代码,那么代码将不会被执行两次。 如果用户拒绝UAC提示,您可以轻松地将其修改为具有特殊行为。 您可以指定修改第四个参数的参数。 您可以指定修改第六个参数的显示方法。底层ShellExecute调用的文档在这里。 相关讨论我不得不使用unicode实例作为ShellExecuteW的参数(如u'runas'和unicode(sys.executable))来运行它。 @Janosch,那是因为你使用的是Python 2.x,而我的代码是在Python 3中(其中所有字符串都被视为unicodes)。但是值得一提,谢谢! @Martin如果我从Windows命令行运行这样的代码:"python yourcode.py"它只是打开python.exe。有办法解决吗? @ user2978216我遇到了同样的问题。在行ctypes.windll.shell32.ShellExecuteW(None,"runas", sys.executable,"", None, 1) sys.executable中只解析python解释器(例如C:\Python27\Python.exe)解决方案是将正在运行的脚本添加为参数(替换"")。 ctypes.windll.shell32.ShellExecuteW(None,"runas", sys.executable, __file__, None, 1)另请注意,为了在python 2.x中工作,所有字符串参数都需要是unicode(即u"runas",unicode(sys.executable)和unicode(__file__)) ShellExecuteW和ShellExecute有什么区别? 谢谢@JavierUbillos,我刚刚编辑了答案 @HrvojeT两者,ShellExecuteW和ShellExecuteA都是对Windows API中ShellExecute函数的调用。前者要求字符串采用unicode格式,后者使用ANSI格式 谢谢。你能告诉我为什么用pyinstaller而不是__file__制作可执行文件时需要空字符串""? 使用py2exe或cx_freeze创建可执行文件,变量__file__不存在。我不是在这里使用空变量,而是用sys.argv[0]替换__file__ @HrvojeT运行python脚本(.py)时,sys.executable解析为PYTHONPATH(e.x C:\Python34\python.exe),因此您需要将文件名作为参数传递。运行转换为可执行文件的脚本时,sys.executable会解析为可执行文件本身,因此不需要参数。此外,由于@deajan提及__file__变量甚至没有在最后一种情况下定义,所以你不应该使用它。 谢谢。为什么不在脚本中使用sys.argv [0],而不是od文件? 我的回答是假设我们实际上并不关心参数。所以,在python脚本中使用sys.argv[0]或__file__都可以。如果您将其转换为可执行文件,则可以使用"","anyrandomstring",sys.argv[0],它也可以正常工作(但不是__file__,因为它未定义)。现在,如果你关心参数,你应该使用"".join(sys.argv)作为python脚本,使用"".join(sys.argv[1:])作为转换后的脚本。 @HrvojeT 请有人告诉我为什么需要try / except块。 是否有可能解析退出状态? @ solstice333是的,确实如此。您可以在文档中查看,ShellExecuteW返回一个整数。如果它等于或大于32,那么一切都没问题,否则你就出错了。 @MartnDelaFuente你看到了并试了一下。在我的ShellExecuteW'ed过程中,我退出1.当我在父进程中使用返回值时,当我期望小于或等于32时,它会让我回到42.忘记在我之前的评论中提到它。 当正在运行的应用程序是使用python -m module而不是脚本运行的python模块时,您将如何使这项工作?
我花了一点时间让dguaraglia的答案正常工作,所以为了节省他人的时间,这就是我为实现这个想法而采取的措施: 12345678910 import osimport sysimport win32com.shell.shell as shellASADMIN = '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) 相关讨论这似乎提升然后退出...如果我输入一些打印语句,他们不会再次执行 这是我见过的最酷的技巧之一。 @JoranBeasley,你不会看到任何输出。 ShellExecuteEx不会将其STDOUT发布回原始shell。在这方面,调试将是......具有挑战性。但特权提升技巧肯定有效。 完美适合我的需求,谢谢! @TimKeating,ActiveState有一个配方,应该使调试更容易:使用DebugView实用程序与标准python日志记录 似乎不可能在同一个控制台中获取输出,但是使用参数nShow = 5到ShellExecuteEx,将使用提升脚本的输出打开一个新的命令窗口。 如果子将其输出重定向到提供的PIPE,则可能是可能的。一些链接stackoverflow.com/questions/4093252/ 一些建议的改进:使用bool(windll.advpack.IsNTAdmin(0, None))来检测当前它是否为admin(使用来自ctypes import windll)。此外,您的params创建还应包括正确的引用,以便带有空格的参数和脚本可以工作。引用每一个是一个好的开始('"'+'""'.join(...)+'"')但是为了更好,你还需要检测参数中的嵌入式引号。 对于引用,您可以使用subprocess.list2cmdline来正确执行此操作。 谢谢,我只需要以管理员身份运行单个子流程,这样就完美了:import win32com.shell.shell as shell shell.ShellExecuteEx(lpVerb='runas', lpFile='net', lpParameters='start service', nShow=5) assert res['hInstApp'] > 32 Microsoft win32-ShellExecuteEx Docs
似乎没有办法提升应用程序权限一段时间来执行特定任务。 Windows需要在程序开始时知道应用程序是否需要某些特权,并要求用户确认应用程序何时执行需要这些特权的任务。有两种方法可以做到这一点: 编写一个清单文件,告诉Windows应用程序可能需要一些权限 从另一个程序内部使用提升的权限运行应用程序这两篇文章更详细地解释了它是如何工作的。 如果您不想为CreateElevatedProcess API编写令人讨厌的ctypes包装器,我会使用代码项目文章中解释的ShellExecuteEx技巧(Pywin32带有ShellExecute的包装器)。怎么样?像这样的东西: 当你的程序启动时,它会检查它是否具有管理员权限,如果它没有使用ShellExecute技巧自行运行并立即退出,如果是,则执行手头的任务。 当您将程序描述为"脚本"时,我认为这足以满足您的需求。 干杯。 相关讨论感谢这些链接,它们对我找到很多关于UAC的东西非常有用。 您可能需要注意的一点是,您可以使用os.startfile($ EXECUTABLE,"runas")在没有PyWin32的情况下执行ShellExecute(我在安装它时遇到了问题)。 @Mike - 但是runas会带来一个新的提示。并且startfile不接受$EXECUTABLE.的命令行参数 我添加了另一个答案,该技术的完整实现应该可以添加到任何python脚本的开头。 第二个链接的文章是"最低权限:使用Windows Vista用户帐户控制教你的应用程序","MSDN Magazine 2007年1月",但此问题现在仅作为.chm文件提供。
认识到这个问题是在几年前被问到的,我认为frmdstryr使用他的模块pyminutils在github上提供了一个更优雅的解决方案: 摘抄: 123456789101112131415161718192021222324252627282930313233 import pythoncomfrom win32com.shell import shell,shellcondef 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接口,并自动指示熟悉的对话框提示需要管理员权限,如果您要复制到需要管理员权限的目录中,您将看到该提示,并在复制操作期间提供典型的文件进度对话框。 相关讨论请在此处查看@frmdstryr的答案:stackoverflow.com/a/19989764/281545
以下示例以MARTIN DE LA FUENTE SAAVEDRA的出色工作和接受的答案为基础。特别是,引入了两个枚举。第一个允许轻松指定如何打开提升的程序,第二个允许在需要轻松识别错误时提供帮助。请注意,如果您希望将所有命令行参数传递给新进程,则sys.argv[0]应该替换为函数调用:subprocess.list2cmdline(sys.argv)。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 #! /usr/bin/env python3import ctypesimport enumimport subprocessimport sys# Reference:# msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx # noinspection SpellCheckingInspectionclass 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 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |