我希望我的Python脚本能够在Vista上复制文件。当我从正常的cmd.exe
窗口运行它时,不会生成错误,但不会复制文件。如果我以管理员身份运行cmd.exe
“然后运行我的脚本,它就可以正常工作。
这是有道理的,因为用户帐户控制(UAC)通常会阻止许多文件系统操作。
有没有办法可以在Python脚本中调用UAC提升请求(这些对话框说“这样的应用程序需要管理员访问权限,这样可以吗?”)
如果那是不可能的,我的脚本是否有办法至少可以检测到它没有升高,以至于它可以优雅地失败?
答案 0 :(得分:63)
我花了一些时间让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)
答案 1 :(得分:63)
截至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)
如果您使用的是Python 2.x,那么您应该替换最后一行:
ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)
另请注意,如果您将python脚本转换为可执行文件(使用py2exe
,cx_freeze
,pyinstaller
等工具),则应将第四个参数替换为空字符串( ""
)。
这里的一些优点是:
ctypes
。底层ShellExecute调用的文档是here。
答案 2 :(得分:28)
似乎没有办法提升应用程序权限一段时间来执行特定任务。 Windows需要在程序开始时知道应用程序是否需要某些权限,并且会要求用户确认应用程序何时执行需要这些权限的任务。有两种方法可以做到这一点:
如果您不想为CreateElevatedProcess API编写令人讨厌的ctypes包装器,我会做的是使用CodePro文章中解释的ShellExecuteEx技巧(Pywin32附带了ShellExecute的包装器)。怎么样?像这样:
当你的程序启动时,会检查它是否具有管理员权限,如果它没有使用ShellExecute技巧自行运行并立即退出,如果有,则执行手头的任务。
当您将程序描述为“脚本”时,我认为这足以满足您的需求。
干杯。
答案 3 :(得分:3)
以下示例建立在 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()
答案 4 :(得分:2)
这可能无法完全回答您的问题,但您也可以尝试使用Elevate Command Powertoy以使用提升的UAC权限运行脚本。
http://technet.microsoft.com/en-us/magazine/2008.06.elevation.aspx
我认为如果你使用它,它看起来就像'提升python yourscript.py'
答案 5 :(得分:1)
如果您的脚本始终需要管理员权限,那么:
runas /user:Administrator "python your_script.py"
答案 6 :(得分:1)
您可以在某处创建快捷方式并作为目标使用: python yourscript.py 然后在属性和高级选择下以管理员身份运行。
当用户执行快捷方式时,它会要求他们提升应用程序。
答案 7 :(得分:1)
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
答案 8 :(得分:1)
这主要是对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:])
答案 9 :(得分:1)
只需添加此答案,以防其他人照原样被Google搜索引导到这里。
我在Python脚本中使用了elevate
模块,在Windows 10中使用Administrator Privileges执行了该脚本。