Search code examples
pythonwindowsadminelevated-privileges

How to run script with elevated privilege on windows


I am writing a pyqt application which require to execute admin task. I would prefer to start my script with elevate privilege. I am aware that this question is asked many times in SO or in other forum. But the solution people are suggesting is to have a look at this SO question Request UAC elevation from within a Python script?

However, I am unable to execute the sample code given in the link. I have put this code on top of the main file and tried to execute it.

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)
print "I am root now."

It actually ask permission to elevate but print line never get executed. Somebody can help me to run the above code successfully.


Solution

  • Update as of 19-02-2023

    The update to the below script is now alive as a Python package by the same author. You can install it from PyPi, which lives at https://pypi.org/project/pyuac/, and the source code/home page is located at https://github.com/Preston-Landers/pyuac. Install it using:

    pip install pyuac
    pip install pypiwin32
    

    Direct usage of the package is:

    import pyuac
    
    def main():
        print("Do stuff here that requires being run as an admin.")
        # The window will disappear as soon as the program exits!
        input("Press enter to close the window. >")
    
    if __name__ == "__main__":
        if not pyuac.isUserAdmin():
            print("Re-launching as admin!")
            pyuac.runAsAdmin()
        else:        
            main()  # Already an admin here.
    

    Or, if you wish to use the decorator:

    from pyuac import main_requires_admin
    
    @main_requires_admin
    def main():
        print("Do stuff here that requires being run as an admin.")
        # The window will disappear as soon as the program exits!
        input("Press enter to close the window. >")
    
    if __name__ == "__main__":
        main()
    

    Original answer

    Thank you all for your reply. I got my script working with the module/script written by Preston Landers in 2010. After two days of browsing the internet, I could find the script. It was deeply hidden in the pywin32 mailing list. With this script, it is easier to check if the user is an admin, and if not, ask for UAC/admin privileges. It provides output in separate windows to display what the code is doing. An example of how to use the code is also included in the script. For the benefit of everyone who's looking for UAC on Windows, take a look at this code. It can be used something like this from your main script:-

    import admin
    
    if not admin.isUserAdmin():
        admin.runAsAdmin()
    

    The actual code (in the module) is:-

    #!/usr/bin/env python
    # -*- coding: utf-8; mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
    # vim: fileencoding=utf-8 tabstop=4 expandtab shiftwidth=4
    
    # (C) COPYRIGHT © Preston Landers 2010
    # Released under the same license as Python 2.6.5
    
     
    import sys, os, traceback, types
     
    def isUserAdmin():
       
        if os.name == 'nt':
            import ctypes
            # WARNING: requires Windows XP SP2 or higher!
            try:
                return ctypes.windll.shell32.IsUserAnAdmin()
            except:
                traceback.print_exc()
                print "Admin check failed, assuming not an admin."
                return False
        elif os.name == 'posix':
            # Check for root on Posix
            return os.getuid() == 0
        else:
            raise RuntimeError, "Unsupported operating system for this module: %s" % (os.name,)
       
    def runAsAdmin(cmdLine=None, wait=True):
     
        if os.name != 'nt':
            raise RuntimeError, "This function is only implemented on Windows."
       
        import win32api, win32con, win32event, win32process
        from win32com.shell.shell import ShellExecuteEx
        from win32com.shell import shellcon
       
        python_exe = sys.executable
     
        if cmdLine is None:
            cmdLine = [python_exe] + sys.argv
        elif type(cmdLine) not in (types.TupleType,types.ListType):
            raise ValueError, "cmdLine is not a sequence."
        cmd = '"%s"' % (cmdLine[0],)
        # XXX TODO: isn't there a function or something we can call to massage command line params?
        params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]])
        cmdDir = ''
        showCmd = win32con.SW_SHOWNORMAL
        #showCmd = win32con.SW_HIDE
        lpVerb = 'runas'  # causes UAC elevation prompt.
       
        # print "Running", cmd, params
     
        # ShellExecute() doesn't seem to allow us to fetch the PID or handle
        # of the process, so we can't get anything useful from it. Therefore
        # the more complex ShellExecuteEx() must be used.
     
        # procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd)
     
        procInfo = ShellExecuteEx(nShow=showCmd,
                                  fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
                                  lpVerb=lpVerb,
                                  lpFile=cmd,
                                  lpParameters=params)
     
        if wait:
            procHandle = procInfo['hProcess']    
            obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE)
            rc = win32process.GetExitCodeProcess(procHandle)
            #print "Process handle %s returned code %s" % (procHandle, rc)
        else:
            rc = None
     
        return rc
     
    def test():
        rc = 0
        if not isUserAdmin():
            print "You're not an admin.", os.getpid(), "params: ", sys.argv
            #rc = runAsAdmin(["c:\\Windows\\notepad.exe"])
            rc = runAsAdmin()
        else:
            print "You are an admin!", os.getpid(), "params: ", sys.argv
            rc = 0
        x = raw_input('Press Enter to exit.')
        return rc
     
     
    if __name__ == "__main__":
        sys.exit(test())