2008-09-25 26 views
59

Tôi muốn tập lệnh Python của tôi sao chép tệp trên Vista. Khi tôi chạy nó từ một cửa sổ cmd.exe bình thường, không có lỗi nào được tạo ra, nhưng các tệp KHÔNG được sao chép. Nếu tôi chạy cmd.exe "làm quản trị viên" và sau đó chạy tập lệnh của tôi, nó hoạt động tốt.Yêu cầu độ cao UAC từ bên trong một tập lệnh Python?

Điều này có ý nghĩa vì Kiểm soát tài khoản người dùng (UAC) thường ngăn chặn nhiều tác vụ của hệ thống tệp.

Có cách nào tôi có thể, từ bên trong một kịch bản Python, gọi một yêu cầu UAC độ cao (những hộp thoại mà nói điều gì đó như "ứng dụng như vậy và như vậy cần truy cập admin, là OK này?")

Nếu đó là không thể, có cách nào kịch bản của tôi ít nhất có thể phát hiện ra rằng nó không được nâng lên để nó có thể thất bại một cách duyên dáng?

+2

http://stackoverflow.com/a/1445547/1628132 sau câu trả lời này bạn tạo một .exe từ kịch bản py sử dụng py2exe và sử dụng một lá cờ gọi là 'uac_info' đó là giải pháp khá gọn gàng – foxcoreg

Trả lời

30

Tính đến năm 2017, một phương pháp dễ dàng để đạt được điều này là như sau:

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, "", None, 1) 

Một số trong những lợi thế ở đây là:

  • Không thư viện bên ngoài yêu cầu (hay Python cho Windows extensi trên). Nó chỉ sử dụng ctypes từ thư viện chuẩn.
  • Hoạt động trên cả Python 2 và Python 3.
  • Không cần phải sửa đổi tài nguyên tệp cũng như tạo tệp kê khai.
  • Nếu bạn không thêm mã bên dưới nếu/else statement, mã sẽ không bao giờ được thực thi hai lần.
  • Bạn có thể dễ dàng sửa đổi nó để có một hành vi đặc biệt nếu người dùng từ chối lời nhắc UAC.
  • Bạn có thể chỉ định đối số sửa đổi tham số thứ tư.
  • Bạn có thể chỉ định phương pháp hiển thị sửa đổi thông số thứ sáu.

Tài liệu cho cuộc gọi ShellExecute bên dưới là here.

+7

Tôi đã phải sử dụng các cá thể unicode làm tham số cho ShellExecuteW (như u'runas 'và unicode (sys.executable)) để chạy nó. – Janosch

+4

@Janosch, đó là bởi vì bạn đang sử dụng Python 2.x, trong khi mã của tôi là trong Python 3 (nơi tất cả các chuỗi được coi là unicodes). Nhưng nó là tốt để đề cập đến, cảm ơn! –

+2

@Martin nếu tôi đang chạy mã này từ dòng lệnh Windows như thế này: "python yourcode.py" nó chỉ mở python.exe. Có cách nào sửa chữa nó không? – user2978216

29

Dường như không có cách nào nâng cao đặc quyền ứng dụng trong một thời gian để bạn có thể thực hiện một tác vụ cụ thể. Windows cần biết khi bắt đầu chương trình cho dù ứng dụng yêu cầu một số đặc quyền và sẽ yêu cầu người dùng xác nhận khi ứng dụng thực hiện bất kỳ tác vụ nào cần cần các đặc quyền đó. Có hai cách để làm điều này:

  1. Viết một file manifest mà nói cho Windows ứng dụng có thể yêu cầu một số đặc quyền
  2. Chạy ứng dụng với quyền cao từ bên trong một chương trình khác

này twoarticles giải thích chi tiết hơn về cách thức hoạt động của nó.

Những gì tôi muốn làm, nếu bạn không muốn viết một wrapper ctypes khó chịu cho API CreateElevatedProcess, hãy sử dụng thủ thuật ShellExecuteEx được giải thích trong bài viết Code Project (Pywin32 đi kèm với trình bao bọc cho ShellExecute). Làm sao? Một cái gì đó như thế này:

Khi chương trình của bạn bắt đầu, nó sẽ kiểm tra nếu nó có đặc quyền của Quản trị viên, nếu nó không tự chạy bằng cách sử dụng thủ thuật ShellExecute và thoát ngay lập tức, nếu có, nó thực hiện nhiệm vụ trong tầm tay.

Khi bạn mô tả chương trình của mình là "tập lệnh", tôi cho rằng đó là đủ cho nhu cầu của bạn.

Chúc mừng.

+0

Cám ơn những liên kết này, chúng rất hữu ích cho tôi tìm hiểu rất nhiều về các công cụ UAC. – Colen

+4

Một cái gì đó bạn có thể muốn lưu ý về điều này là bạn có thể làm ShellExecute mà không cần PyWin32 (tôi đã có vấn đề nhận được nó được cài đặt) bằng cách sử dụng os.startfile ($ EXECUTABLE, "runas"). –

+0

@Mike - nhưng 'runas' mang đến một dấu nhắc mới mặc dù. Và startfile không chấp nhận các đối số dòng lệnh để '$ EXECUTABLE.' –

1

Nếu kịch bản của bạn luôn luôn đòi hỏi đặc quyền của một quản trị viên thì:

runas /user:Administrator "python your_script.py" 
+12

cẩn thận, độ cao! = Chạy với tư cách là quản trị viên – Kugel

+0

Tôi mới dùng python ... bạn có thể cho tôi biết tôi sẽ đặt mã đó ở đâu? –

+0

@RahatIslamKhan: Mở cửa sổ Dấu nhắc Lệnh và đặt ở đó: lệnh chạy 'your_script.py' làm người dùng Quản trị viên. Đảm bảo bạn hiểu [@ Kugel's comment] (http://stackoverflow.com/questions/130763/request-uac-elevation-from-within-a-python-script/138970?noredirect=1#comment4664946_138970). – jfs

58

Nó đã cho tôi một chút thời gian để có được câu trả lời dguaraglia của làm việc, do đó vì lợi ích của tiết kiệm thời gian người khác , đây là những gì tôi đã làm để thực hiện ý tưởng này:

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

điều này dường như nâng cao và sau đó thoát ra ... nếu tôi đưa vào một số báo cáo in họ không được thực hiện một lần thứ hai –

+2

Đây là một trong những thủ thuật thú vị nhất mà tôi từng thấy. –

+6

@JoranBeasley, bạn sẽ không thấy bất kỳ đầu ra nào. ShellExecuteEx không đăng STDOUT của nó trở lại shell gốc. Về khía cạnh đó, gỡ lỗi sẽ là ... thách thức. Nhưng thủ thuật đặc quyền nâng cấp chắc chắn hoạt động. –

1

Bạn có thể tạo một shortcut ở đâu đó và như việc sử dụng mục tiêu: python yourscript.py sau đó thuộc tính và chọn nâng cao chạy với tư cách quản trị viên.

Khi người dùng thực hiện lối tắt, nó sẽ yêu cầu họ nâng cấp ứng dụng.

4

năm Nhận câu hỏi này đã được hỏi trước, tôi nghĩ rằng một giải pháp thanh lịch được cung cấp trên github bởi frmdstryr sử dụng pyminutils mô-đun của mình:

Trích:

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  

này sử dụng giao diện COM và tự động chỉ ra rằng đặc quyền quản trị là cần thiết với lời nhắc thoại quen thuộc mà bạn sẽ thấy nếu bạn đang sao chép vào một thư mục nơi đặc quyền quản trị được yêu cầu và cũng cung cấp hộp thoại tiến trình tập tin điển hình trong quá trình sao chép.

+0

Xem câu trả lời của @frmdstryr tại đây: http: //stackoverflow.com/a/19989764/281545 –

1

Một biến thể của công việc Jorenko của trên cho phép quá trình cao để sử dụng cùng một giao diện điều khiển (nhưng xem nhận xét của tôi dưới đây):

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 
+0

Xin lỗi. tùy chọn bàn điều khiển tương tự (SEE_MASK_NO_CONSOLE) chỉ hoạt động nếu bạn đã nâng cấp. Lỗi của tôi. – Berwyn

1

Ví dụ sau đây được xây dựng trên MARTIN DE LA FUENTE của SAAVEDRA công việc tuyệt vời và câu trả lời được chấp nhận. Đặc biệt, hai bảng liệt kê được giới thiệu. Việc đầu tiên cho phép dễ dàng xác định một chương trình nâng cao được mở ra như thế nào, và điều thứ hai giúp khi các lỗi cần được xác định dễ dàng. Xin lưu ý rằng nếu bạn muốn tất cả đối số dòng lệnh được chuyển đến quy trình mới, có thể thay thế sys.argv[0] bằng lệnh gọi hàm: subprocess.list2cmdline(sys.argv).

#! /usr/bin/env python3 
import ctypes 
import enum 
import sys 


# Reference: 
# msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx 


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: 
     hinstance = ctypes.windll.shell32.ShellExecuteW(
      None, 'runas', sys.executable, sys.argv[0], None, SW.SHOWNORMAL 
     ) 
     if hinstance <= 32: 
      raise RuntimeError(ERROR(hinstance)) 


def main(): 
    # Your Code Here 
    print(input('Echo: ')) 


if __name__ == '__main__': 
    bootstrap() 
Các vấn đề liên quan