it-swarm.com.de

Fordern Sie die UAC-Erhöhung in einem Python Skript an?

Ich möchte, dass mein Python - Skript Dateien unter Vista kopiert. Wenn ich es von einem normalen cmd.exe Fenster, es werden keine Fehler generiert, die Dateien werden jedoch NICHT kopiert. Wenn ich cmd.exe "als Administrator" und dann mein Skript ausführen, funktioniert es gut.

Dies ist sinnvoll, da die Benutzerkontensteuerung (User Account Control, UAC) normalerweise viele Dateisystemaktionen verhindert.

Gibt es eine Möglichkeit, wie ich aus einem Python Skript heraus eine UAC-Erhöhungsanforderung aufrufen kann?

Wenn das nicht möglich ist, kann mein Skript dann zumindest erkennen, dass es nicht erhöht ist, sodass es ordnungsgemäß fehlschlagen kann?

78
jwfearn

Ab 2017 ist eine einfache Methode, dies zu erreichen, die folgende:

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)

Wenn Sie Python 2.x verwenden, sollten Sie die letzte Zeile ersetzen für:

ctypes.windll.Shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

Beachten Sie auch, dass Sie python script in eine ausführbare Datei konvertiert haben (mit Tools wie py2exe, cx_freeze, pyinstaller), dann sollten Sie den vierten Parameter für eine leere Zeichenfolge ersetzen ("").

Einige der Vorteile sind hier:

  • Keine externen Bibliotheken erforderlich (oder Python für Windows-Erweiterung). Verwendet nur ctypes aus der Standardbibliothek.
  • Funktioniert mit Python 2 und Python 3.
  • Es ist nicht erforderlich, die Dateiressourcen zu ändern oder eine Manifestdatei zu erstellen.
  • Wenn Sie keinen Code unterhalb der if/else-Anweisung hinzufügen, wird der Code niemals zweimal ausgeführt.
  • Sie können es leicht ändern, um ein spezielles Verhalten zu erzielen, wenn der Benutzer die UAC-Eingabeaufforderung ablehnt.
  • Sie können Argumente angeben, die den vierten Parameter ändern.
  • Sie können die Anzeigemethode angeben, indem Sie den sechsten Parameter ändern.

Die Dokumentation für den zugrunde liegenden ShellExecute-Aufruf lautet hier .

72

Es hat eine Weile gedauert, bis die Antwort von Dguaraglia funktioniert hat. Um anderen Zeit zu sparen, habe ich Folgendes getan, um diese Idee umzusetzen:

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)
64
Jorenko

Es scheint, als gäbe es keine Möglichkeit, die Anwendungsberechtigungen für eine Weile zu erhöhen, damit Sie eine bestimmte Aufgabe ausführen können. Windows muss beim Start des Programms wissen, ob für die Anwendung bestimmte Berechtigungen erforderlich sind, und fordert den Benutzer auf, zu bestätigen, wann die Anwendung Aufgaben ausführt, die erforderlich sind diese Privilegien. Hierfür gibt es zwei Möglichkeiten:

  1. Schreiben Sie eine Manifestdatei, die Windows mitteilt, dass für die Anwendung möglicherweise einige Berechtigungen erforderlich sind
  2. Führen Sie die Anwendung mit erhöhten Rechten in einem anderen Programm aus

Diese zweiArtikel erklären viel detaillierter, wie dies funktioniert.

Was ich tun würde, wenn Sie keinen bösen C-Typ-Wrapper für die CreateElevatedProcess-API schreiben möchten, ist die Verwendung des ShellExecuteEx-Tricks, der im Artikel zum Code-Projekt erläutert wird (Pywin32 wird mit einem Wrapper für ShellExecute geliefert). Wie? Etwas wie das:

Wenn Ihr Programm startet, prüft es, ob es über Administratorrechte verfügt, wenn es sich nicht selbst mithilfe des ShellExecute-Tricks ausführt, und beendet es sofort, wenn dies der Fall ist, führt es die jeweilige Aufgabe aus.

Da Sie Ihr Programm als "Skript" bezeichnen, reicht das für Ihre Anforderungen aus.

Prost.

29
dguaraglia

In Anbetracht der Tatsache, dass diese Frage vor Jahren gestellt wurde, wird am github von frmdstryr mit seinem Modul pyminutils eine elegantere Lösung angeboten:

Auszug:

import pythoncom
from win32com.Shell import Shell,shellcon

def 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    

Dies nutzt die COM-Schnittstelle und zeigt automatisch an, dass Administratorrechte mit dem vertrauten Dialogfeld erforderlich sind. Aufforderung, dass Sie sehen würden, ob Sie in ein Verzeichnis kopieren, in dem Administratorrechte erforderlich sind, und bietet außerdem das typische Dialogfeld für den Dateiverlauf während des Kopiervorgangs.

4
KenV99

Das folgende Beispiel baut auf MARTIN DE LA FUENTE SAAVEDRA exzellenter Arbeit und akzeptierter Antwort auf. Insbesondere werden zwei Aufzählungen eingeführt. Die erste ermöglicht eine einfache Spezifikation, wie ein erweitertes Programm geöffnet werden soll, und die zweite hilft, wenn Fehler leicht identifiziert werden müssen. Bitte beachten Sie, dass, wenn alle Befehlszeilenargumente an den neuen Prozess übergeben werden sollen, sys.argv[0] Wahrscheinlich durch einen Funktionsaufruf ersetzt werden sollte: 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 __== '__main__':
    bootstrap()
3
Noctis Skytower

Dies beantwortet Ihre Frage möglicherweise nicht vollständig, aber Sie können auch versuchen, das Elevate Command Powertoy zu verwenden, um das Skript mit erhöhten UAC-Berechtigungen auszuführen.

http://technet.Microsoft.com/en-us/magazine/2008.06.elevation.aspx

Ich denke, wenn Sie es verwenden, würde es aussehen wie 'elevate python yourscript.py'

2
TinyGrasshopper

Eine Variation von Jorenkos Arbeit oben ermöglicht es dem erhöhten Prozess, dieselbe Konsole zu verwenden (siehe meinen Kommentar unten):

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
1
Berwyn

Sie können irgendwo eine Verknüpfung erstellen und als Ziel verwenden: python yourscript.py dann unter Eigenschaften und erweiterte Auswahl als Administrator ausführen.

Wenn der Benutzer die Verknüpfung ausführt, fordert er ihn auf, die Anwendung zu öffnen.

1
officialhopsof

Dies ist hauptsächlich ein Upgrade von Jorenkos Antwort, das die Verwendung von Parametern mit Leerzeichen in Windows ermöglicht, aber auch unter Linux recht gut funktionieren sollte :) Funktioniert auch mit cx_freeze oder py2exe, da wir nicht __file__ Verwenden, sondern sys.argv[0] Als ausführbare Datei

import sys,ctypes,platform

def is_admin():
    try:
        return ctypes.windll.Shell32.IsUserAnAdmin()
    except:
        raise False

if __== '__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:])
1
Orsiris de Jong

Wenn für Ihr Skript immer Administratorrechte erforderlich sind, gehen Sie wie folgt vor:

runas /user:Administrator "python your_script.py"
1
jfs