How to run script with elevated privilege on windows

193,885

Solution 1

Thank you all for your reply. I have got my script working with the module/ script written by Preston Landers way back in 2010. After two days of browsing the internet I could find the script as it was was deeply hidden in pywin32 mailing list. With this script it is easier to check if the user is admin and if not then ask for UAC/ admin right. It does provide output in separate windows to find out what the code is doing. Example on how to use the code also included in the script. For the benefit of all who all are looking for UAC on windows have a look at this code. I hope it helps someone looking for same solution. It can be used something like this from your main script:-

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

The actual code 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())

Solution 2

in comments to the answer you took the code from someone says ShellExecuteEx doesn't post its STDOUT back to the originating shell. so you will not see "I am root now", even though the code is probably working fine.

instead of printing something, try writing to a file:

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)
with open("somefilename.txt", "w") as out:
    print >> out, "i am root"

and then look in the file.

Solution 3

I found a very easy solution to this problem.

  1. Create a shortcut for python.exe
  2. Change the shortcut target into something like C:\xxx\...\python.exe your_script.py
  3. Click "advance..." in the property panel of the shortcut, and click the option "run as administrator"

I'm not sure whether the spells of these options are right, since I'm using Chinese version of Windows.

Solution 4

Here is a solution which needed ctypes module only. Support pyinstaller wrapped program.

#!python
# coding: utf-8
import sys
import ctypes

def run_as_admin(argv=None, debug=False):
    shell32 = ctypes.windll.shell32
    if argv is None and shell32.IsUserAnAdmin():
        return True

    if argv is None:
        argv = sys.argv
    if hasattr(sys, '_MEIPASS'):
        # Support pyinstaller wrapped program.
        arguments = map(unicode, argv[1:])
    else:
        arguments = map(unicode, argv)
    argument_line = u' '.join(arguments)
    executable = unicode(sys.executable)
    if debug:
        print 'Command line: ', executable, argument_line
    ret = shell32.ShellExecuteW(None, u"runas", executable, argument_line, None, 1)
    if int(ret) <= 32:
        return False
    return None


if __name__ == '__main__':
    ret = run_as_admin()
    if ret is True:
        print 'I have admin privilege.'
        raw_input('Press ENTER to exit.')
    elif ret is None:
        print 'I am elevating to admin privilege.'
        raw_input('Press ENTER to exit.')
    else:
        print 'Error(ret=%d): cannot elevate privilege.' % (ret, )

Solution 5

Here is a solution with an stdout redirection:

def elevate():
    import ctypes, win32com.shell.shell, win32event, win32process
    outpath = r'%s\%s.out' % (os.environ["TEMP"], os.path.basename(__file__))
    if ctypes.windll.shell32.IsUserAnAdmin():
        if os.path.isfile(outpath):
            sys.stderr = sys.stdout = open(outpath, 'w', 0)
        return
    with open(outpath, 'w+', 0) as outfile:
        hProc = win32com.shell.shell.ShellExecuteEx(lpFile=sys.executable, \
            lpVerb='runas', lpParameters=' '.join(sys.argv), fMask=64, nShow=0)['hProcess']
        while True:
            hr = win32event.WaitForSingleObject(hProc, 40)
            while True:
                line = outfile.readline()
                if not line: break
                sys.stdout.write(line)
            if hr != 0x102: break
    os.remove(outpath)
    sys.stderr = ''
    sys.exit(win32process.GetExitCodeProcess(hProc))

if __name__ == '__main__':
    elevate()
    main()
Share:
193,885
sundar_ima
Author by

sundar_ima

Updated on July 05, 2022

Comments

  • sundar_ima
    sundar_ima almost 2 years

    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. Thanks in advance.

  • sundar_ima
    sundar_ima over 10 years
    But it never bring up my pyqt window at all. Tested the code with ZetCode zetcode.com/gui/pyqt4/firstprograms
  • Ecno92
    Ecno92 over 10 years
    Thank you very much for this answer. I had the problem that my Qt GUI did not show up completely when it was executed with shellexecuteEX, your extensive command with the showcommand helped me to make it work. Thanks! :)
  • frmdstryr
    frmdstryr over 9 years
    Thank you,had to add the nShow and fMask params for it to work with a Qt gui.
  • Elvis Teixeira
    Elvis Teixeira over 8 years
    Very good, I was trying to figure out how to do it right now to write a installer for my app.
  • tomSurge
    tomSurge over 8 years
    Hello, it does ask for elevation, but once I click yes, the program for some odd reason runs twice. Any input on that?
  • Mr_and_Mrs_D
    Mr_and_Mrs_D almost 8 years
    Can you post a link to in pywin32 mailing list the code comes from ??
  • sundar_ima
    sundar_ima almost 8 years
    This question/answer was posted almost 3 years back. Now I really don't have the link..
  • David Callanan
    David Callanan over 7 years
    how to not have an extra empty console? is this possible? thanks
  • BuvinJ
    BuvinJ about 7 years
    It runs twice because the first time it's launching a new instance of the program as an admin. You need to exit the program if his function doesn't return True. Or, you might change this a bit to launch a different program, using this one just a "launch pad".
  • deenbandhu
    deenbandhu almost 7 years
    but this prompt for permission. Is there any way i can skip that
  • Niklas R
    Niklas R over 6 years
    Thank you! Is there a way to get the new process' output in the original terminal and not open an additional window?
  • Hrvoje T
    Hrvoje T about 6 years
    Here is the same script forked on github for python3 gist.github.com/sylvainpelissier/…
  • Anonymous
    Anonymous about 4 years
    How can I run the elevated process as another detached process so that the orignal program can quit?
  • takanuva15
    takanuva15 almost 4 years
    @HrvojeT thank you for that! It took me ages to figure out how to run python processes as admin
  • Deepak Yadav
    Deepak Yadav over 3 years
    The way could also be explained as : Run your python as admin then execute the scripts. Then automatically all the scripts would have the admin access.
  • Mark Ransom
    Mark Ransom over 3 years
    @deenbandhu if you could skip the prompt, every virus ever written would do that and you'd be constantly infected. That's a feature that's never going to go away.
  • CircleOnCircles
    CircleOnCircles over 2 years
    This resulted in an error, python 3.8 ``` File ".\main.py", line 26, in elevate with open(outpath, 'w+', 0) as outfile: ValueError: can't have unbuffered text I/O```