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


94

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

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

Python 스크립트 내에서 UAC 권한 상승 요청을 호출 할 수있는 방법이 있습니까 ( "그런 앱에 관리자 액세스가 필요합니다.

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


3
stackoverflow.com/a/1445547/1628132 이 답변에 따라 py2exe를 사용하고 'uac_info'라는 플래그를 사용하여 .py 스크립트에서 .exe를 생성하는 것은 매우 깔끔한 솔루션입니다
foxcoreg

답변:


99

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, " ".join(sys.argv), None, 1)

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

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

또한 실행 파일로 당신에게 파이썬 스크립트를 변환하면 있습니다 (같은 도구를 사용하여는 py2exe, cx_freeze, pyinstaller) 당신은 사용해야하는 sys.argv[1:]대신 sys.argv네 번째 매개 변수에.

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

  • 외부 라이브러리가 필요하지 않습니다. 그것은 단지 용도 ctypessys표준 라이브러리에서.
  • Python 2와 Python 3 모두에서 작동합니다.
  • 파일 리소스를 수정하거나 매니페스트 파일을 만들 필요가 없습니다.
  • if / else 문 아래에 코드를 추가하지 않으면 코드가 두 번 실행되지 않습니다.
  • 마지막 줄에서 API 호출의 반환 값을 가져와 실패 할 경우 조치를 취할 수 있습니다 (코드 <= 32). 여기에서 가능한 반환 값을 확인 하십시오 .
  • 여섯 번째 매개 변수를 수정하여 생성 된 프로세스의 표시 방법을 변경할 수 있습니다.

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


9
나는 이것을 실행하기 위해 ShellExecuteW (u'runas '및 unicode (sys.executable)와 같은)의 매개 변수로 유니 코드 인스턴스를 사용해야했습니다.
Janosch

6
@Janosch는 Python 2.x를 사용하고 있지만 내 코드는 Python 3 (모든 문자열이 유니 코드로 처리됨)에 있기 때문입니다. 그러나 언급하는 것이 좋습니다, 감사합니다!
Martín De la Fuente

2
@Martin 다음과 같이 Windows 명령 줄에서이 코드를 실행하는 경우 "python yourcode.py"는 python.exe를 엽니 다. 그것을 고칠 방법이 있습니까?
user2978216 dec.

1
@ user2978216 같은 문제가 발생했습니다. 줄 ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, "", None, 1) sys.executable에서 파이썬 인터프리터로만 해석됩니다 (예 C:\Python27\Python.exe:) 해결책은 실행중인 스크립트를 인수로 추가하는 것입니다 (을 대체 ""). ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)또한 파이썬 2.X에서이 작업을 수행하려면, 모든 문자열 인수가 유니 코드 할 필요가 있습니다 (즉 u"runas", unicode(sys.executable)unicode(__file__))
하비에르 Ubillos

2
@HrvojeT 둘 다 ShellExecuteW및 Windows API ShellExecuteAShellExecute함수에 대한 호출 입니다. 전자는 문자열이 유니 코드 형식이어야하고 후자는 ANSI 형식으로 사용됩니다.
Martín De la Fuente 2018

71

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)

1
이것은 단지 상승한 다음 종료하는 것 같습니다 ... 인쇄 문을 몇 개 넣으면 두 번째로 실행되지 않습니다
Joran Beasley

6
@JoranBeasley, 출력이 표시되지 않습니다. ShellExecuteEx는 STDOUT을 원래 셸에 다시 게시하지 않습니다. 그런 점에서 디버깅은 ... 어려울 것입니다. 그러나 권한을 얻는 트릭은 확실히 작동합니다.
Tim Keating

1
: @TimKeating,은 ActiveState는 좀 더 쉽게 디버깅해야 조리법이 표준 파이썬 로깅을 사용 DebugView와 유틸리티
samwyse

1
동일한 콘솔에서 출력을 얻는 것이 불가능 해 보이지만 ShellExecuteEx에 대한 nShow = 5 인수를 사용하면 상승 된 스크립트의 출력과 함께 새 명령 창이 열립니다.
Emil Styrke 2014

2
인용의 subprocess.list2cmdline경우 올바르게 사용 하여 사용할 수 있습니다 .
coderforlife 2015-08-27

29

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

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

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

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

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

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

건배.


그 링크들 덕분에 UAC에 대해 많은 것을 알아내는 데 매우 유용했습니다.
Colen

4
이것에 대해 주목하고 싶은 것은 os.startfile ($ EXECUTABLE, "runas")을 사용하여 PyWin32없이 ShellExecute를 수행 할 수 있다는 것입니다 (설치하는 데 문제가있었습니다).
Mike McQuaid

@Mike-하지만 runas새로운 프롬프트가 나타납니다. 그리고 startfile은 명령 줄 인수를 허용하지 않습니다$EXECUTABLE.
Sridhar Ratnakumar 2011 년

모든 파이썬 스크립트의 시작 부분에 추가 할 수 있어야하는이 기술의 전체 구현으로 또 다른 답변을 추가했습니다.
Jorenko 2012

두 번째 링크에 대한 기사는 "MSDN Magazine 2007 년 1 월"의 "최소 권한 : Windows Vista 사용자 계정 컨트롤을 사용하여 앱이 멋지게 실행되도록 교육"이었지만 이제이 문제는 .chm파일 로만 제공됩니다 .
피터

6

다른 사람들이 Google 검색에서 여기로 안내하는 경우이 답변을 추가하십시오. elevatePython 스크립트 의 모듈과 Windows 10에서 관리자 권한으로 실행 된 스크립트를 사용했습니다 .

https://pypi.org/project/elevate/


이봐 요, elevate모듈을 사용해 보았는데 "시스템에서 파일에 액세스 할 수 없습니다"라는 오류 메시지가 나타납니다. 그 이유는 무엇입니까?
paxos1977

@ paxos1977 그 오류를 보여주는 코드 스 니펫을 게시 할 수 있습니까? 감사!
Irving Moy

5

다음 예제는 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()

4

이 질문이 몇 년 전에 질문되었다는 것을 인식하면 frmdstryr가 pywinutils 모듈을 사용하여 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 인터페이스를 활용하고 관리자 권한이 필요한 디렉토리로 복사하는 경우 볼 수있는 친숙한 대화 상자 프롬프트를 통해 관리자 권한이 필요함을 자동으로 나타내며 복사 작업 중에 일반적인 파일 진행 대화 상자를 제공합니다.



2

어딘가에 바로 가기를 만들 수 있으며 대상으로 python yourscript.py 다음 속성 및 고급 선택에서 관리자 권한으로 실행을 선택할 수 있습니다.

사용자가 바로 가기를 실행하면 응용 프로그램을 높이도록 요청합니다.


1

스크립트에 항상 관리자 권한이 필요한 경우 :

runas /user:Administrator "python your_script.py"

15
조심하세요, 상승! = 관리자 권한으로 실행
Kugel

저는 파이썬을 처음 접했습니다 ... 그 코드를 어디에 넣을지 말씀해 주시겠습니까?
Rahat Islam Khan

@RahatIslamKhan : 명령 프롬프트 창을 열고 다음 위치에 넣으십시오. 명령은 your_script.py관리자 사용자로 실행 됩니다. @Kugel의 의견 을 이해했는지 확인하십시오 .
jfs

1

위의 Jorenko의 작업에 대한 변형을 통해 상승 된 프로세스가 동일한 콘솔을 사용할 수 있습니다 (하지만 아래의 내 의견 참조).

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

죄송합니다. 동일한 콘솔 옵션 (SEE_MASK_NO_CONSOLE)은 이미 승격 된 경우에만 작동합니다. 내 잘못이야.
Berwyn

1

이것은 대부분의 Windows에 공백이 매개 변수를 사용할 수 있습니다 Jorenko의 대답에 업그레이드이지만, 또한 우리가 사용하지 않기 때문에 나 cx_Freeze 또는 py2exe에 함께 작동합니다, 또한 : 리눅스에서 꽤 잘 작동해야 __file__하지만 sys.argv[0]실행 파일과

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:])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.