Request UAC elevation from within a Python script?

前端 未结 11 643

I want my Python script to copy files on Vista. When I run it from a normal cmd.exe window, no errors are generated, yet the files are NOT copied. If I run

相关标签:
11条回答
  • 2020-11-22 05:41

    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:])
    
    0 讨论(0)
  • 2020-11-22 05:45

    It seems there's no way to elevate the application privileges for a while for you to perform a particular task. Windows needs to know at the start of the program whether the application requires certain privileges, and will ask the user to confirm when the application performs any tasks that need those privileges. There are two ways to do this:

    1. Write a manifest file that tells Windows the application might require some privileges
    2. Run the application with elevated privileges from inside another program

    This two articles explain in much more detail how this works.

    What I'd do, if you don't want to write a nasty ctypes wrapper for the CreateElevatedProcess API, is use the ShellExecuteEx trick explained in the Code Project article (Pywin32 comes with a wrapper for ShellExecute). How? Something like this:

    When your program starts, it checks if it has Administrator privileges, if it doesn't it runs itself using the ShellExecute trick and exits immediately, if it does, it performs the task at hand.

    As you describe your program as a "script", I suppose that's enough for your needs.

    Cheers.

    0 讨论(0)
  • 2020-11-22 05:46

    As of 2017, an easy method to achieve this is the following:

    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)
    

    If you are using Python 2.x, then you should replace the last line for:

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

    Also note that if you converted you python script into an executable file (using tools like py2exe, cx_freeze, pyinstaller) then you should use sys.argv[1:] instead of sys.argv in the fourth parameter.

    Some of the advantages here are:

    • No external libraries required. It only uses ctypes and sys from standard library.
    • Works on both Python 2 and Python 3.
    • There is no need to modify the file resources nor creating a manifest file.
    • If you don't add code below if/else statement, the code won't ever be executed twice.
    • You can get the return value of the API call in the last line and take an action if it fails (code <= 32). Check possible return values here.
    • You can change the display method of the spawned process modifying the sixth parameter.

    Documentation for the underlying ShellExecute call is here.

    0 讨论(0)
  • 2020-11-22 05:46

    The following example builds on MARTIN DE LA FUENTE SAAVEDRA's excellent work and accepted answer. In particular, two enumerations are introduced. The first allows for easy specification of how an elevated program is to be opened, and the second helps when errors need to be easily identified. Please note that if you want all command line arguments passed to the new process, sys.argv[0] should probably be replaced with a function call: 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()
    
    0 讨论(0)
  • 2020-11-22 05:52

    Just adding this answer in case others are directed here by Google Search as I was. I used the elevate module in my Python script and the script executed with Administrator Privileges in Windows 10.

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

    0 讨论(0)
提交回复
热议问题