Chcę, aby mój skrypt w Pythonie kopiował pliki w systemie Vista. Kiedy uruchamiam go z normalnego cmd.exe
okna, żadne błędy nie są generowane, ale pliki NIE są kopiowane. Jeśli uruchomię cmd.exe
„jako administrator”, a następnie uruchomię skrypt, wszystko działa dobrze.
Ma to sens, ponieważ Kontrola konta użytkownika (UAC) zwykle zapobiega wielu działaniom w systemie plików.
Czy istnieje sposób, w jaki mogę, z poziomu skryptu Python, wywołać żądanie podniesienia uprawnień UAC (te okna dialogowe, które mówią coś w rodzaju „taka a taka aplikacja wymaga dostępu administratora, czy to jest w porządku?”)
Jeśli nie jest to możliwe, czy istnieje sposób, w jaki mój skrypt może przynajmniej wykryć, że nie jest podniesiony, aby mógł z wdziękiem zawieść?
python
windows
windows-vista
uac
jwfearn
źródło
źródło
Odpowiedzi:
Od 2017 r. Prostą metodą osiągnięcia tego jest:
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, " ".join(sys.argv), None, 1)
Jeśli używasz Pythona 2.x, powinieneś zamienić ostatnią linię na:
ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(" ".join(sys.argv)), None, 1)
Należy również pamiętać, że jeśli ci skrypt Pythona konwertowane do pliku wykonywalnego (za pomocą narzędzi takich jak
py2exe
,cx_freeze
,pyinstaller
), należy użyćsys.argv[1:]
zamiastsys.argv
w czwartym parametrem.Oto niektóre z zalet:
ctypes
isys
ze standardowej biblioteki.Dokumentacja dotycząca podstawowego wywołania ShellExecute jest tutaj .
źródło
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, "", None, 1)
sys.executable
rozwiązuje się tylko interpreter Pythona (np.C:\Python27\Python.exe
) Rozwiązaniem jest dodanie uruchomionego skryptu jako argumentu (replacting""
).ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Należy również pamiętać, aby to działało w Pythonie 2.x, wszystkie argumenty strun muszą być Unicode (tju"runas"
,unicode(sys.executable)
iunicode(__file__)
)ShellExecuteW
iShellExecuteA
są wywołaniamiShellExecute
funkcji w interfejsie API systemu Windows. Pierwsza z nich zobowiązuje ciągi do formatu unicode, a druga jest używana z formatem ANSIZajęło mi trochę czasu, zanim odpowiedź dguaraglii zadziałała, więc aby zaoszczędzić czas innym, oto co zrobiłem, aby wdrożyć ten pomysł:
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)
źródło
subprocess.list2cmdline
aby zrobić to poprawnie.Wygląda na to, że nie ma sposobu, aby na chwilę podnieść uprawnienia aplikacji, aby wykonać określone zadanie. System Windows musi wiedzieć na początku programu, czy aplikacja wymaga określonych uprawnień, i poprosi użytkownika o potwierdzenie, kiedy aplikacja wykonuje zadania wymagające tych uprawnień. Można to zrobić na dwa sposoby:
Te dwa artykuły wyjaśniają bardziej szczegółowo, jak to działa.
Jeśli nie chcesz pisać paskudnego opakowania ctypes dla interfejsu API CreateElevatedProcess, użyj sztuczki ShellExecuteEx wyjaśnionej w artykule Code Project (Pywin32 jest dostarczany z opakowaniem dla ShellExecute). W jaki sposób? Coś takiego:
Kiedy program się uruchamia, sprawdza, czy ma uprawnienia administratora, jeśli nie, uruchamia się sam za pomocą sztuczki ShellExecute i natychmiast kończy pracę, jeśli tak, wykonuje zadanie.
Ponieważ opisujesz swój program jako „skrypt”, przypuszczam, że to wystarczy na Twoje potrzeby.
Twoje zdrowie.
źródło
runas
wyświetla nowy monit. A plik startowy nie akceptuje argumentów wiersza poleceń do$EXECUTABLE.
.chm
pliku.Po prostu dodaję tę odpowiedź na wypadek, gdyby inni zostali skierowani tutaj przez wyszukiwarkę Google, tak jak ja. Użyłem
elevate
modułu w moim skrypcie Python i skrypcie wykonanym z uprawnieniami administratora w systemie Windows 10.https://pypi.org/project/elevate/
źródło
elevate
modułu i otrzymuję błąd „System nie może uzyskać dostępu do pliku”, czy masz jakieś pomysły, dlaczego tak się stało?Poniższy przykład opiera się na doskonałej pracy MARTIN DE LA FUENTE SAAVEDRA i zaakceptowanej odpowiedzi. W szczególności wprowadzono dwa wyliczenia. Pierwsza pozwala na łatwe określenie sposobu otwierania programu z podwyższonym poziomem uprawnień, a druga pomaga, gdy trzeba łatwo zidentyfikować błędy. Pamiętaj, że jeśli chcesz, aby wszystkie argumenty wiersza polecenia przekazywane do nowego procesu,
sys.argv[0]
prawdopodobnie powinien zostać zastąpiony przez wywołanie funkcji: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()
źródło
Uznając to pytanie został poproszony lat temu, myślę, że bardziej eleganckie rozwiązanie jest oferowane na github przez frmdstryr wykorzystując swoje pywinutils module:
Fragment:
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
Wykorzystuje to interfejs COM i automatycznie wskazuje, że potrzebne są uprawnienia administratora, w znanym oknie dialogowym, które można zobaczyć, gdyby kopiowano do katalogu, w którym wymagane są uprawnienia administratora, a także wyświetla typowe okno dialogowe postępu pliku podczas operacji kopiowania.
źródło
Może to nie odpowiadać całkowicie na Twoje pytanie, ale możesz również spróbować użyć Elevate Command Powertoy, aby uruchomić skrypt z podwyższonymi uprawnieniami UAC.
http://technet.microsoft.com/en-us/magazine/2008.06.elevation.aspx
Myślę, że gdybyś go użył, wyglądałoby to tak, jakbyś to zrobił „podnieś pythona yourscript.py”
źródło
Możesz gdzieś zrobić skrót i jako cel użyć: python yourscript.py, a następnie we właściwościach i wybierz zaawansowane, uruchom jako administrator.
Gdy użytkownik wykona skrót, poprosi go o podniesienie poziomu aplikacji.
źródło
Jeśli twój skrypt zawsze wymaga uprawnień administratora, to:
runas /user:Administrator "python your_script.py"
źródło
your_script.py
jako użytkownik administratora. Upewnij się, że rozumiesz komentarz @ Kugel .Odmiana powyższej pracy Jorenko umożliwia podwyższonemu procesowi korzystanie z tej samej konsoli (ale zobacz mój komentarz poniżej):
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
źródło
Jest to głównie aktualizacja odpowiedzi Jorenko, która pozwala na użycie parametrów ze spacjami w Windows, ale powinna również działać całkiem dobrze na Linuksie :) Również będzie działać z cx_freeze lub py2exe, ponieważ nie używamy,
__file__
alesys.argv[0]
jako wykonywalneimport 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:])
źródło