web-dev-qa-db-fra.com

Comment exécuter un script python avec des privilèges élevés sur Windows

J'écris une application pyqt qui nécessite l'exécution de tâches administratives. Je préférerais commencer mon script avec le privilège Elevate. Je suis conscient que cette question est posée à plusieurs reprises dans SO ou dans un autre forum. Mais la solution proposée par les utilisateurs consiste à examiner cette question SO Demander l’élévation du contrôle de compte utilisateur à partir d’un script Python?

Cependant, je suis incapable d'exécuter l'exemple de code donné dans le lien. J'ai mis ce code au-dessus du fichier principal et j'ai essayé de l'exécuter. 

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 fait, il demande la permission d’élever mais la ligne d’impression n’est jamais exécutée. Quelqu'un peut m'aider à exécuter le code ci-dessus avec succès. Merci d'avance.

41
sundar_ima

Merci à tous pour votre réponse. Mon script fonctionne avec le module/script écrit par Preston Landers en 2010. Après deux jours de navigation sur Internet, je pouvais le trouver car il était profondément caché dans la liste de diffusion pywin32. Avec ce script, il est plus facile de vérifier si l'utilisateur est admin et sinon, demandez le droit UAC/admin. Il fournit une sortie dans des fenêtres séparées pour savoir ce que fait le code. Exemple d'utilisation du code également inclus dans le script. Pour le bénéfice de tous ceux qui recherchent tous le code UAC sous Windows, consultez ce code. J'espère que cela aidera quelqu'un qui recherche la même solution. Vous pouvez utiliser quelque chose comme ceci depuis votre script principal: -

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

Le code actuel est: -

#!/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 __== "__main__":
    sys.exit(test())
62
sundar_ima

dans les commentaires de la réponse vous avez pris le code quelqu'un dit que ShellExecuteEx n'envoie pas son STDOUT au shell d'origine. vous ne verrez donc pas "Je suis root maintenant", même si le code fonctionne probablement bien.

au lieu d’imprimer quelque chose, essayez d’écrire dans un fichier:

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"

puis regardez dans le fichier.

8
andrew cooke

Voici une solution avec une redirection 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 __== '__main__':
    elevate()
    main()
6
Florent B.

Voici une solution qui nécessitait uniquement le module ctypes. Supporte le programme encapsulé 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 __== '__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, )
5
Gary Lee

J'ai trouvé une solution très facile à ce problème.

  1. Créer un raccourci pour python.exe
  2. Changez la cible du raccourci en quelque chose comme C:\xxx\...\python.exe your_script.py
  3. Cliquez sur "avancer ..." dans le panneau des propriétés du raccourci, puis cliquez sur l'option "exécuter en tant qu'administrateur".

Je ne suis pas sûr que les options de ces options soient correctes, car j'utilise la version chinoise de Windows.

1
delphifirst

Aussi, si votre répertoire de travail est différent de celui que vous pouvez utiliser lpDirectory

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

Sera utile si changer le chemin n’est pas une option souhaitable Remove unicode for python 3.X

0
Pranav

Je peux confirmer que la solution proposée par delphifirst fonctionne et constitue la solution la plus simple et la plus simple au problème de l’exécution d’un script python avec des privilèges élevés.

J'ai créé un raccourci vers l'exécutable python (python.exe), puis modifié le raccourci en ajoutant le nom de mon script après l'appel à python.exe. Ensuite, j'ai coché "Exécuter en tant qu'administrateur" dans "l'onglet de compatibilité" du raccourci. Lorsque le raccourci est exécuté, vous recevez une invite demandant l'autorisation d'exécuter le script en tant qu'administrateur.

Mon application python particulière était un programme d’installation. Le programme permet d'installer et de désinstaller une autre application python. Dans mon cas, j'ai créé deux raccourcis, l'un nommé "appname install" et l'autre nommé "appname uninstall". La seule différence entre les deux raccourcis est l'argument qui suit le nom du script python. Dans la version du programme d'installation, l'argument est "install". Dans la version de désinstallation, l'argument est "uninstall". Le code dans le script du programme d’installation évalue l’argument fourni et appelle la fonction appropriée (installer ou désinstaller) selon les besoins.

J'espère que mes explications aideront les autres à comprendre plus rapidement comment exécuter un script Python avec des privilèges élevés.

0
John Moore