Cómo ejecutar un script de Python con privilegios elevados en Windows

Estoy escribiendo una aplicación pyqt que requiere ejecutar la tarea de administración. Preferiría comenzar mi guión con privilegio elevado. Soy consciente de que esta pregunta se hace muchas veces en SO o en otro foro. Pero la solución que la gente está sugiriendo es echar un vistazo a esta elevación de UAC de la pregunta SO desde un script de Python.

Sin embargo, no puedo ejecutar el código de muestra dado en el enlace. He puesto este código encima del archivo principal y he intentado ejecutarlo.

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) print "I am root now." 

En realidad, pide permiso para elevar, pero la línea de impresión nunca se ejecuta. Alguien me puede ayudar a ejecutar el código anterior con éxito. Gracias por adelantado.

Gracias a todos por su respuesta. Tengo mi script que trabaja con el módulo / script escrito por Prestn Landers en 2010. Después de dos días de navegar por Internet, pude encontrar el script, ya que estaba muy escondido en la lista de correo de pywin32. Con este script es más fácil verificar si el usuario es administrador y, de no ser así, solicitar el derecho de UAC / administrador. Proporciona salida en ventanas separadas para averiguar qué está haciendo el código. Ejemplo de cómo usar el código también incluido en el script. Para el beneficio de todos los que buscan UAC en Windows, eche un vistazo a este código. Espero que ayude a alguien que busca la misma solución. Se puede usar algo así desde tu script principal:

 import admin if not admin.isUserAdmin(): admin.runAsAdmin() 

El código real es: –

 #!/usr/bin/env python # -*- coding: utf-8; mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- # vim: fileencoding=utf-8 tabstop=4 expandtab shiftwidth=4 # (C) COPYRIGHT © Prestn Landers 2010 # Released under the same license as Python 2.6.5 import sys, os, traceback, types def isUserAdmin(): if os.name == 'nt': import ctypes # WARNING: requires Windows XP SP2 or higher! try: return ctypes.windll.shell32.IsUserAnAdmin() except: traceback.print_exc() print "Admin check failed, assuming not an admin." return False elif os.name == 'posix': # Check for root on Posix return os.getuid() == 0 else: raise RuntimeError, "Unsupported operating system for this module: %s" % (os.name,) def runAsAdmin(cmdLine=None, wait=True): if os.name != 'nt': raise RuntimeError, "This function is only implemented on Windows." import win32api, win32con, win32event, win32process from win32com.shell.shell import ShellExecuteEx from win32com.shell import shellcon python_exe = sys.executable if cmdLine is None: cmdLine = [python_exe] + sys.argv elif type(cmdLine) not in (types.TupleType,types.ListType): raise ValueError, "cmdLine is not a sequence." cmd = '"%s"' % (cmdLine[0],) # XXX TODO: isn't there a function or something we can call to massage command line params? params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]]) cmdDir = '' showCmd = win32con.SW_SHOWNORMAL #showCmd = win32con.SW_HIDE lpVerb = 'runas' # causes UAC elevation prompt. # print "Running", cmd, params # ShellExecute() doesn't seem to allow us to fetch the PID or handle # of the process, so we can't get anything useful from it. Therefore # the more complex ShellExecuteEx() must be used. # procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd) procInfo = ShellExecuteEx(nShow=showCmd, fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, lpVerb=lpVerb, lpFile=cmd, lpParameters=params) if wait: procHandle = procInfo['hProcess'] obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) rc = win32process.GetExitCodeProcess(procHandle) #print "Process handle %s returned code %s" % (procHandle, rc) else: rc = None return rc def test(): rc = 0 if not isUserAdmin(): print "You're not an admin.", os.getpid(), "params: ", sys.argv #rc = runAsAdmin(["c:\\Windows\\notepad.exe"]) rc = runAsAdmin() else: print "You are an admin!", os.getpid(), "params: ", sys.argv rc = 0 x = raw_input('Press Enter to exit.') return rc if __name__ == "__main__": sys.exit(test()) 

en los comentarios a la respuesta, tomó el código de alguien que dice que ShellExecuteEx no publica su STDOUT de nuevo en el shell de origen . por lo que no verá “Soy root ahora”, aunque el código probablemente funcione bien.

En lugar de imprimir algo, intente escribir en un archivo:

 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) with open("somefilename.txt", "w") as out: print >> out, "i am root" 

y luego mirar en el archivo.

Aquí hay una solución con una redirección stdout:

 def elevate(): import ctypes, win32com.shell.shell, win32event, win32process outpath = r'%s\%s.out' % (os.environ["TEMP"], os.path.basename(__file__)) if ctypes.windll.shell32.IsUserAnAdmin(): if os.path.isfile(outpath): sys.stderr = sys.stdout = open(outpath, 'w', 0) return with open(outpath, 'w+', 0) as outfile: hProc = win32com.shell.shell.ShellExecuteEx(lpFile=sys.executable, \ lpVerb='runas', lpParameters=' '.join(sys.argv), fMask=64, nShow=0)['hProcess'] while True: hr = win32event.WaitForSingleObject(hProc, 40) while True: line = outfile.readline() if not line: break sys.stdout.write(line) if hr != 0x102: break os.remove(outpath) sys.stderr = '' sys.exit(win32process.GetExitCodeProcess(hProc)) if __name__ == '__main__': elevate() main() 

Aquí hay una solución que solo necesita el módulo ctypes. Soporta el progtwig envuelto pyinstaller.

 #!python # coding: utf-8 import sys import ctypes def run_as_admin(argv=None, debug=False): shell32 = ctypes.windll.shell32 if argv is None and shell32.IsUserAnAdmin(): return True if argv is None: argv = sys.argv if hasattr(sys, '_MEIPASS'): # Support pyinstaller wrapped program. arguments = map(unicode, argv[1:]) else: arguments = map(unicode, argv) argument_line = u' '.join(arguments) executable = unicode(sys.executable) if debug: print 'Command line: ', executable, argument_line ret = shell32.ShellExecuteW(None, u"runas", executable, argument_line, None, 1) if int(ret) <= 32: return False return None if __name__ == '__main__': ret = run_as_admin() if ret is True: print 'I have admin privilege.' raw_input('Press ENTER to exit.') elif ret is None: print 'I am elevating to admin privilege.' raw_input('Press ENTER to exit.') else: print 'Error(ret=%d): cannot elevate privilege.' % (ret, ) 

He encontrado una solución muy fácil a este problema.

  1. Crear un acceso directo para python.exe
  2. Cambie el destino del acceso directo en algo como C:\xxx\...\python.exe your_script.py
  3. Haga clic en “avanzar …” en el panel de propiedades del acceso directo y haga clic en la opción “Ejecutar como administrador”

No estoy seguro de si los hechizos de estas opciones son correctos, ya que estoy usando la versión china de Windows.

Puedo confirmar que la solución de delphifirst funciona y es la solución más fácil y sencilla para el problema de ejecutar un script de Python con privilegios elevados.

Creé un acceso directo al ejecutable de python (python.exe) y luego modifiqué el acceso directo agregando el nombre de mi script después de la llamada a python.exe. A continuación, marque “ejecutar como administrador” en la “pestaña de compatibilidad” del acceso directo. Cuando se ejecuta el acceso directo, aparece un mensaje solicitando permiso para ejecutar el script como administrador.

Mi aplicación particular de Python era un progtwig de instalación. El progtwig permite instalar y desinstalar otra aplicación de python. En mi caso, creé dos accesos directos, uno llamado “appname install” y el otro llamado “appname uninstall”. La única diferencia entre los dos accesos directos es el argumento que sigue al nombre del script de python. En la versión del instalador el argumento es “instalar”. En la versión de desinstalación el argumento es “desinstalar”. El código en el script del instalador evalúa el argumento proporcionado y llama a la función apropiada (instalar o desinstalar) según sea necesario.

Espero que mi explicación ayude a otros a descubrir más rápidamente cómo ejecutar un script de python con privilegios elevados.

Además, si su directorio de trabajo es diferente al que puede usar lpDirectory

  procInfo = ShellExecuteEx(nShow=showCmd, lpVerb=lpVerb, lpFile=cmd, lpDirectory= unicode(direc), lpParameters=params) 

Será útil si cambiar la ruta no es una opción deseable, elimine Unicode para Python 3.X