Python windows task to run with admin - python

I am looking for some Python code to create a Windows Task in the Task Scheduler, it needs to run at start & have the highest permissions level (admin).
// description of your code here
Uses the new COM Task Scheduler Interface to create a new disabled scheduled task, then run it once as part of a script. Use this to launch interactive tasks, even remotely.
import win32com.client
computer_name = "" #leave all blank for current computer, current user
computer_username = ""
computer_userdomain = ""
computer_password = ""
action_id = "Test Task" #arbitrary action ID
action_path = r"c:\windows\system32\calc.exe" #executable path (could be python.exe)
action_arguments = r'' #arguments (could be something.py)
action_workdir = r"c:\windows\system32" #working directory for action executable
author = "Someone" #so that end users know who you are
description = "testing task" #so that end users can identify the task
task_id = "Test Task"
task_hidden = False #set this to True to hide the task in the interface
username = ""
password = ""
run_flags = "TASK_RUN_NO_FLAGS" #see dict below, use in combo with username/password
#define constants
TASK_TRIGGER_DAILY = 2
TASK_CREATE = 2
TASK_CREATE_OR_UPDATE = 6
TASK_ACTION_EXEC = 0
IID_ITask = "{148BD524-A2AB-11CE-B11F-00AA00530503}"
RUNFLAGSENUM = {
"TASK_RUN_NO_FLAGS" : 0,
"TASK_RUN_AS_SELF" : 1,
"TASK_RUN_IGNORE_CONSTRAINTS" : 2,
"TASK_RUN_USE_SESSION_ID" : 4,
"TASK_RUN_USER_SID" : 8
}
#connect to the scheduler (Vista/Server 2008 and above only)
scheduler = win32com.client.Dispatch("Schedule.Service")
scheduler.Connect(computer_name or None, computer_username or None, computer_userdomain or None, computer_password or None)
rootFolder = scheduler.GetFolder("\\")
#(re)define the task
taskDef = scheduler.NewTask(0)
colTriggers = taskDef.Triggers
trigger = colTriggers.Create(TASK_TRIGGER_DAILY)
trigger.DaysInterval = 100
trigger.StartBoundary = "2100-01-01T08:00:00-00:00" #never start
trigger.Enabled = False
colActions = taskDef.Actions
action = colActions.Create(TASK_ACTION_EXEC)
action.ID = action_id
action.Path = action_path
action.WorkingDirectory = action_workdir
action.Arguments = action_arguments
info = taskDef.RegistrationInfo
info.Author = author
info.Description = description
settings = taskDef.Settings
settings.Enabled = False
settings.Hidden = task_hidden
#register the task (create or update, just keep the task name the same)
result = rootFolder.RegisterTaskDefinition(task_id, taskDef, TASK_CREATE_OR_UPDATE, "", "", RUNFLAGSENUM[run_flags] ) #username, password
#run the task once
task = rootFolder.GetTask(task_id)
task.Enabled = True
runningTask = task.Run("")
task.Enabled = False
This code creates a task to run daily, but not at login & not as admin. Is there any way I can do this without requiring the UAC Prompt to open at startup?
EDIT: I am NOT looking to just make the program ask for administrator, as the prompt will popup, as specified above. I need it to have the highest execution level in the WINDOWS EVENT SCHEDULER to run at logon.

I think it would be a good idea for you to build a Batch file running python and your script. Having done that there are a few things that you might want to try, i haven't personally had the time to try them out but here you go:
Compile the .BAT file and make it an .exe once you do that i think you should be able to involve your task scheduler into the mix and get your code running whenever you need.
If nothing works you can always mess around with your window's registry to allow your script to bypass the prompt using a Windows Registry Editor.
Do look it up before you execute as this is code I have found elsewhere, but it should do the trick:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{E2F13B98-650F-47DB-845A-420A1ED34EC7}User\Software\Microsoft\Windows\CurrentVersion\Policies\Associations]
"LowRiskFileTypes"=".exe;.bat;.cmd;.vbs"
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Associations]
"LowRiskFileTypes"=".exe;.bat;.cmd;.vbs"

After searching Google more thoroughly, I came across a command that does exactly what I need.
schtasks.exe /create /S COMPUTERNAME /RU "NT AUTHORITY\SYSTEM" /RL HIGHEST /SC ONLOGON /TN "Administrative OnLogon Script" /TR "cscript.exe \"Path\To\Script.vbs\""
All I need to do is replace the computer name, and program to execute and it makes the task perfectly. I can execute it in a elevated Python environment to create it.

Related

Submitting parallel jobs on HTCondor, using python

I am trying to submit parallel jobs in a loop on HTCondor, following is a simple example of the python script -
test_mus = np.linspace(0, 5, 10)
results = [pyhf.infer.hypotest(test_mu, data, model)
for test_mu in test_mus]
I would like to submit each job (results), over the for loop (so 10 jobs) simultaneously to 10 machines, and then combine all the results in a pickle.
I have the submission script for this job as below -
executable = CLs.sh
+JobFlavour = "testmatch"
arguments = $(ClusterId) $(ProcId)
Input = LHpruned_NEW_32.json
output = output_sigbkg/CLs.$(ClusterId).$(ProcId).out
error = output_sigbkg/CLs.$(ClusterId).$(ProcId).err
log = output_sigbkg/CLs.$(ClusterId).log
transfer_input_files = CLs_test1point.py, LHpruned_NEW_32.json
should_transfer_files = YES
queue
I would like to know how to submit 10 jobs, to parallelize the jobs.
Thank you !
Best,
Shreya
It's worth looking at the description of how to submit a HTCondor DAG via Python here. In your case, if you install the htcondor Python module, you could do something like:
import htcondor
from htcondor import dags
# create the submit script
sub = htcondor.Submit(
{
"executable": "CLs.sh",
"+JobFlavour": "testmatch",
"arguments": "$(ClusterId) $(ProcId)",
"Input": "LHpruned_NEW_32.json",
"output": "output_sigbkg/CLs.$(ClusterId).$(ProcId).out",
"error": "output_sigbkg/CLs.$(ClusterId).$(ProcId).err",
"log": "output_sigbkg/CLs.$(ClusterId).log",
"transfer_input_files": "CLs_test1point.py, LHpruned_NEW_32.json",
"should_transfer_files": "YES",
}
)
# create DAG
dag = dags.DAG()
# add layer with 10 jobs
layer = dag.layer(
name="CLs_layer",
submit_description=sub,
vars=[{} for i in range(10)],
)
# write out the DAG to current directory
dagfile = dags.write_dag(dag, ".")
You can use the vars argument to add macros giving values for each specific job if you want, e.g., if you wanted mu as one of the executable arguments you could switch this to:
import htcondor
from htcondor import dags
# create the submit script
sub = htcondor.Submit(
{
"executable": "CLs.sh",
"+JobFlavour": "testmatch",
"arguments": "$(ClusterId) $(ProcId) $(MU)",
"Input": "LHpruned_NEW_32.json",
"output": "output_sigbkg/CLs.$(ClusterId).$(ProcId).out",
"error": "output_sigbkg/CLs.$(ClusterId).$(ProcId).err",
"log": "output_sigbkg/CLs.$(ClusterId).log",
"transfer_input_files": "CLs_test1point.py, LHpruned_NEW_32.json",
"should_transfer_files": "YES",
}
)
# create DAG
dag = dags.DAG()
# add layer with 10 jobs
layer = dag.layer(
name="CLs_layer",
submit_description=sub,
vars=[{"MU": mu} for mu in np.linspace(0, 5, 10)],
)
# write out the DAG to current directory
dagfile = dags.write_dag(dag, ".")
Once the DAG is created, you can either submit it as normal with condor_submit_dag from the terminal, or submit it via Python using the instructions here.
Note: your +JobFlavour value for the submit file will actually get converted to MY.JobFlavour in the file that gets created, but that's ok and means the same thing.

Django run scheduled jobs hourly

In my project I have to load data in database hourly .I tried celery and cron but found all the stuff very complicated and always createes some issue.I use pycharm in windows. I am new to django and just need a simple solution to run the following command hourly.
This loads data in dabase.
"python manage.py fetchfiles"
management/commands/fetchfiles
from django.core.management.base import BaseCommand, CommandError
from dashboard.models import airdata as tdata
import requests
import json
class Command(BaseCommand):
help = 'Fetches api data'
"""def add_arguments(self, parser):
none"""
def handle(self, *args, **options):
#for a in range(0,1578,10):
a = True
offno = 0
lst2=[]
dict1={}
while a == True:
api_key = "579b464db66ec23bdd000001cdd3946e44ce4aad7209ff7b23ac571b"
url = "https://api.data.gov.in/resource/3b01bcb8-0b14-4abf-b6f2-c1bfd384ba69?api-key={}&format=json&offset={}&limit=10".format(api_key,offno)
response = requests.get(url)
data = response.text
a1=json.loads(data)
for ele in a1['records']:
if ele['pollutant_min'] == 'NA':
dict1['pol_min'] = 0
else:
dict1['pol_min'] = int(ele['pollutant_min'])
if ele['pollutant_max'] == 'NA':
dict1['pol_max'] = 0
else:
dict1['pol_max'] = int(ele['pollutant_max'])
if ele['pollutant_avg'] == 'NA':
dict1['pol_avg'] = 0
else:
dict1['pol_avg'] = int(ele['pollutant_avg'])
dict1['state'] = ele['state']
dict1['city'] = ele['city']
dict1['station'] = ele['station']
dict1['time_vector'] = ele['last_update']
lst2.append(dict1.copy())
if a1["count"] < 10:
a= False
offno += 10
airx = json.dumps(lst2, indent=1)
tdata.objects.bulk_create([tdata(**vals) for vals in lst2])
return airx
You have 2 ways
Adding it to crontab on Unix systems or scheduled task on Windows.
Using Celery Beat
Celery is probably more complex than you need just to run something like his hourly. You've already discovered writing management commands. Just wrap the management command in a shell script and (on Unix/Linux) get cron to run it hourly. You need to make sure that the shell script stays "quiet" when it succeeds, but makes any failures very apparent so it's not sitting there failing with nobody noticing.
Can't advise what to do on Windows, but I think it has task scheduling.

Python PowerPoint SaveAs Task Scheduler

I have automated the creation of a PowerPoint slide-deck via Python and have set-up a trigger in Task Scheduler for a daily report to be generated.
This is all fine while my computer is logged in, but the script fails when the setting: "Run whether is logged in or not".
I checked to see what line was at fault and it turns out it is this one:
Presentation.SaveAs('C:\\Users\\me\\Desktop\\test.pptx')
I am running Task Scheduler with highest priority but it only runs this task with the "User is logged in" state.
Below is the entire basic code segment for reference:
import win32com.client, MSO, MSPPT, sys, os
g = globals()
for c in dir(MSO.constants): g[c] = getattr(MSO.constants, c)
for c in dir(MSPPT.constants): g[c] = getattr(MSPPT.constants, c)
error_file = open('C:\\Users\\me\\Desktop\\error_file.txt', 'wb')
run = False
try:
Application = win32com.client.Dispatch("PowerPoint.Application")
Application.Visible = True
Presentation = Application.Presentations.Add()
Slide = Presentation.Slides.Add(1, ppLayoutBlank)
Presentation.SaveAs('C:\\Users\\me\\Desktop\\test.pptx')
Presentation.Close()
Application.Quit()
run = True
except:
run = False
if run == True:
error_file.write('ok')
else:
error_file.write('fail')
Any help on this would be much appreciated.
Thanks,
JP

Copying a file in python : Permission denied [duplicate]

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 cmd.exe "as administator" and then run my script, it works fine.
This makes sense since User Account Control (UAC) normally prevents many file system actions.
Is there a way I can, from within a Python script, invoke a UAC elevation request (those dialogs that say something like "such and such app needs admin access, is this OK?")
If that's not possible, is there a way my script can at least detect that it is not elevated so it can fail gracefully?
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.
It took me a little while to get dguaraglia's answer working, so in the interest of saving others time, here's what I did to implement this idea:
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)
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:
Write a manifest file that tells Windows the application might require some privileges
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.
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/
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()
Recognizing this question was asked years ago, I think a more elegant solution is offered on github by frmdstryr using his module pywinutils:
Excerpt:
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
This utilizes the COM interface and automatically indicates that admin privileges are needed with the familiar dialog prompt that you would see if you were copying into a directory where admin privileges are required and also provides the typical file progress dialog during the copy operation.
This may not completely answer your question but you could also try using the Elevate Command Powertoy in order to run the script with elevated UAC privileges.
http://technet.microsoft.com/en-us/magazine/2008.06.elevation.aspx
I think if you use it it would look like 'elevate python yourscript.py'
You can make a shortcut somewhere and as the target use:
python yourscript.py
then under properties and advanced select run as administrator.
When the user executes the shortcut it will ask them to elevate the application.
A variation on Jorenko's work above allows the elevated process to use the same console (but see my comment below):
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
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
[EDIT]
Disclaimer: The code in this post is outdated.
I have published the elevation code as a python package.
Install with pip install command_runner
Usage:
from command_runner.elevate import elevate
def main():
"""My main function that should be elevated"""
print("Who's the administrator, now ?")
if __name__ == '__main__':
elevate(main)
[/EDIT]
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:])
For one-liners, put the code to where you need UAC.
Request UAC, if failed, keep running:
import ctypes, sys
ctypes.windll.shell32.IsUserAnAdmin() or ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32 and exit()
Request UAC, if failed, exit:
import ctypes, sys
ctypes.windll.shell32.IsUserAnAdmin() or (ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32, exit())
Function style:
# Created by BaiJiFeiLong#gmail.com at 2022/6/24
import ctypes
import sys
def request_uac_or_skip():
ctypes.windll.shell32.IsUserAnAdmin() or ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32 and sys.exit()
def request_uac_or_exit():
ctypes.windll.shell32.IsUserAnAdmin() or (ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32, sys.exit())
If your script always requires an Administrator's privileges then:
runas /user:Administrator "python your_script.py"

Request UAC elevation from within a Python script?

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 cmd.exe "as administator" and then run my script, it works fine.
This makes sense since User Account Control (UAC) normally prevents many file system actions.
Is there a way I can, from within a Python script, invoke a UAC elevation request (those dialogs that say something like "such and such app needs admin access, is this OK?")
If that's not possible, is there a way my script can at least detect that it is not elevated so it can fail gracefully?
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.
It took me a little while to get dguaraglia's answer working, so in the interest of saving others time, here's what I did to implement this idea:
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)
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:
Write a manifest file that tells Windows the application might require some privileges
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.
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/
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()
Recognizing this question was asked years ago, I think a more elegant solution is offered on github by frmdstryr using his module pywinutils:
Excerpt:
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
This utilizes the COM interface and automatically indicates that admin privileges are needed with the familiar dialog prompt that you would see if you were copying into a directory where admin privileges are required and also provides the typical file progress dialog during the copy operation.
This may not completely answer your question but you could also try using the Elevate Command Powertoy in order to run the script with elevated UAC privileges.
http://technet.microsoft.com/en-us/magazine/2008.06.elevation.aspx
I think if you use it it would look like 'elevate python yourscript.py'
You can make a shortcut somewhere and as the target use:
python yourscript.py
then under properties and advanced select run as administrator.
When the user executes the shortcut it will ask them to elevate the application.
A variation on Jorenko's work above allows the elevated process to use the same console (but see my comment below):
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
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
[EDIT]
Disclaimer: The code in this post is outdated.
I have published the elevation code as a python package.
Install with pip install command_runner
Usage:
from command_runner.elevate import elevate
def main():
"""My main function that should be elevated"""
print("Who's the administrator, now ?")
if __name__ == '__main__':
elevate(main)
[/EDIT]
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:])
For one-liners, put the code to where you need UAC.
Request UAC, if failed, keep running:
import ctypes, sys
ctypes.windll.shell32.IsUserAnAdmin() or ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32 and exit()
Request UAC, if failed, exit:
import ctypes, sys
ctypes.windll.shell32.IsUserAnAdmin() or (ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32, exit())
Function style:
# Created by BaiJiFeiLong#gmail.com at 2022/6/24
import ctypes
import sys
def request_uac_or_skip():
ctypes.windll.shell32.IsUserAnAdmin() or ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32 and sys.exit()
def request_uac_or_exit():
ctypes.windll.shell32.IsUserAnAdmin() or (ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1) > 32, sys.exit())
If your script always requires an Administrator's privileges then:
runas /user:Administrator "python your_script.py"

Categories