program tip

Python 스크립트 내에서 UAC 상승을 요청 하시겠습니까?

radiobox 2020. 10. 7. 07:30
반응형

Python 스크립트 내에서 UAC 상승을 요청 하시겠습니까?


내 Python 스크립트가 Vista에서 파일을 복사하기를 원합니다. 일반 cmd.exe에서 실행하면 오류가 생성되지 않지만 파일은 복사되지 않습니다. 내가 실행하면 cmd.exe"administator로"다음 내 스크립트를 실행, 그것을 잘 작동합니다.

이는 UAC (사용자 계정 컨트롤)가 일반적으로 많은 파일 시스템 작업을 방지하기 때문에 의미가 있습니다.

Python 스크립트 내에서 UAC 권한 상승 요청을 호출 할 수있는 방법이 있습니까 ( "그러한 앱에 관리자 액세스가 필요합니다. 괜찮습니까?"와 같은 대화 상자).

그것이 가능하지 않다면, 내 스크립트가 적어도 상승되지 않았 음을 감지하여 정상적으로 실패 할 수있는 방법이 있습니까?


2017 년 현재이를 달성하는 쉬운 방법은 다음과 같습니다.

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)

Python 2.x를 사용하는 경우 다음의 마지막 줄을 바꿔야합니다.

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

또한 실행 파일로 당신에게 파이썬 스크립트를 변환하면 있습니다 (같은 도구를 사용하여가 py2exe, cx_freeze, pyinstaller) 다음 빈 문자열에 대한 네 번째 매개 변수를 교체해야합니다 ( "").

여기에 몇 가지 장점은 다음과 같습니다.

  • 외부 라이브러리가 필요하지 않습니다 (Windows 용 Python 확장도 필요 없음). ctypes표준 라이브러리 에서만 사용 합니다.
  • Python 2와 Python 3 모두에서 작동합니다.
  • 파일 리소스를 수정하거나 매니페스트 파일을 만들 필요가 없습니다.
  • if / else 문 아래에 코드를 추가하지 않으면 코드가 두 번 실행되지 않습니다.
  • 사용자가 UAC 프롬프트를 거부하는 경우 특별한 동작을 갖도록 쉽게 수정할 수 있습니다.
  • 네 번째 매개 변수를 수정하는 인수를 지정할 수 있습니다.
  • 여섯 번째 매개 변수를 수정하여 표시 방법을 지정할 수 있습니다.

기본 ShellExecute 호출에 대한 문서는 여기에 있습니다 .


dguaraglia의 답변이 작동하는 데 약간의 시간이 걸렸으므로 다른 사람들의 시간을 절약하기 위해이 아이디어를 구현하기 위해 다음과 같이했습니다.

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)

특정 작업을 수행하기 위해 잠시 동안 응용 프로그램 권한을 높일 수있는 방법이없는 것 같습니다. Windows는 프로그램을 시작할 때 응용 프로그램에 특정 권한이 필요한지 여부를 알아야하며 응용 프로그램이 이러한 권한 필요한 작업을 수행 할 때 사용자에게 확인하도록 요청합니다 . 이를 수행하는 두 가지 방법이 있습니다.

  1. 응용 프로그램에 몇 가지 권한이 필요할 수 있음을 Windows에 알리는 매니페스트 파일 작성
  2. 다른 프로그램 내에서 상승 된 권한으로 응용 프로그램 실행

기사는 이것이 어떻게 작동하는지 훨씬 더 자세히 설명합니다.

CreateElevatedProcess API에 대해 불쾌한 ctypes 래퍼를 작성하지 않으려면 코드 프로젝트 문서에 설명 된 ShellExecuteEx 트릭을 사용하면됩니다 (Pywin32에는 ShellExecute 용 래퍼가 함께 제공됨). 어떻게? 이 같은:

프로그램이 시작될 때 관리자 권한이 있는지 확인하고, ShellExecute 트릭을 사용하여 자체적으로 실행되지 않으면 즉시 종료하고, 있으면 즉시 작업을 수행합니다.

귀하의 프로그램을 "스크립트"로 설명 할 때 그 정도면 충분하다고 생각합니다.

건배.


이 질문이 몇 년 전에 질문되었다는 것을 인식하면 frmdstryr이 pyminutils 모듈을 사용하여 github 에서 더 우아한 솔루션을 제공한다고 생각합니다 .

발췌 :

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    

이것은 COM 인터페이스를 활용하고 관리자 권한이 필요한 디렉토리로 복사하는 경우 볼 수있는 친숙한 대화 상자 프롬프트로 관리자 권한이 필요함을 자동으로 나타내며 복사 작업 중에 일반적인 파일 진행 대화 상자를 제공합니다.


다음 예제는 MARTIN DE LA FUENTE SAAVEDRA의 뛰어난 작업과 수용된 답변을 기반으로합니다. 특히 두 개의 열거 형이 도입되었습니다. 첫 번째는 상승 된 프로그램을 여는 방법을 쉽게 지정할 수 있도록하고 두 번째는 오류를 쉽게 식별해야 할 때 도움이됩니다. 모든 명령 줄 인수를 새 프로세스로 전달하려면 sys.argv[0]함수 호출로 대체해야합니다 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()

This may not completely answer your question but you could also try using the Elevate Command Powertoy in order to run the script with elevated UAC privileges.

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

I think if you use it it would look like 'elevate python yourscript.py'


If your script always requires an Administrator's privileges then:

runas /user:Administrator "python your_script.py"

You can make a shortcut somewhere and as the target use: python yourscript.py then under properties and advanced select run as administrator.

When the user executes the shortcut it will ask them to elevate the application.


A variation on Jorenko's work above allows the elevated process to use the same console (but see my comment below):

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

This is mostly an upgrade to Jorenko's answer, that allows to use parameters with spaces in Windows, but should also work fairly well on Linux :) Also, will work with cx_freeze or py2exe since we don't use __file__ but sys.argv[0] as executable

import 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:])

참고URL : https://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script

반응형