Cómo ejecutar script python con privilegios elevados en Windows


Estoy escribiendo una aplicación pyqt que requiere ejecutar la tarea admin. Preferiría comenzar mi guión con elevate privilege. Soy consciente de que esta pregunta se hace muchas veces en tal o cual foro. Pero la solución que la gente está sugiriendo es echar un vistazo a esta pregunta ¿Solicitar la elevación de UAC desde un script Python?

Sin embargo, no puedo ejecutar el código de ejemplo 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 puede ayudarme a ejecutar el código anterior con éxito. Gracias de antemano.

Author: Community, 2013-10-30

7 answers

Gracias a todos por su respuesta. Tengo mi guión trabajando con el módulo / guión escrito por Preston Landers en 2010. Después de dos días de navegar por Internet, pude encontrar el script tal como estaba profundamente oculto en la lista de correo de pywin32. Con este script es más fácil comprobar si el usuario es administrador y si no, entonces preguntar por UAC/ admin derecho. 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 todos están buscando UAC en Windows echar un vistazo a este código. Espero que ayude a alguien que busca la misma solución. Se puede usar algo como esto desde su 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 © Preston 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())
 61
Author: sundar_ima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-01 01:06:42

En los comentarios a la respuesta tomaste el código de alguien dice ShellExecuteEx no envía su salida estándar al shell de origen. así que no verás "Soy root ahora", a pesar de que el código probablemente está funcionando 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 busque en el archivo.

 8
Author: andrew cooke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:29

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()
 6
Author: Florent B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-20 06:11:37

Aquí hay una solución que solo necesitaba el módulo ctypes. Soporte pyinstaller envuelto programa.

#!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, )
 4
Author: Gary Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-22 14:58:34

Encontré una solución muy fácil a este problema.

  1. Crear un acceso directo para python.exe
  2. Cambie el objetivo de acceso directo a 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.

 0
Author: delphifirst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-21 15:49:49

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

He creado un acceso directo al ejecutable de python (python.exe) y luego modificó el atajo agregando el nombre de mi script después de la llamada a python.exe. A continuación, he marcado "ejecutar como administrador" en la "pestaña de compatibilidad" del acceso directo. Cuando se ejecuta el acceso directo, se obtiene un mensaje pidiendo permiso para ejecutar el script como un administrador.

Mi aplicación particular de python era un programa de instalación. El programa permite instalar y desinstalar otra aplicación python. En mi caso he creado 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 python. En la versión del instalador el argumento es "install". En la versión de desinstalación el argumento es "desinstalar". El código en el script de instalación evalúa el argumento suministrado 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 python con privilegios elevados.

 0
Author: John Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-06 17:32:33

También si su directorio de trabajo es diferente de lo que puede utilizar 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 eliminar unicode para python 3.X

 0
Author: Pranav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-28 06:13:36