Code: Select all
/*
_ _ _ __ __ _ _ _ _
| |__ | |_ | |_ _ __ _ / // /__ _ | |__ | | __ ___ ___ _ __ (_) _ __ | |_ ___ _ __ __ _
| '_ \ | __|| __|| '_ \(_) / // // _` || '_ \ | |/ // __| / __|| '__|| || '_ \ | __| / _ \ | '__|/ _` |
| | | || |_ | |_ | |_) |_ / // /| (_| || | | || < \__ \| (__ | | | || |_) || |_ _| (_) || | | (_| |
|_| |_| \__| \__|| .__/(_)_//_/ \__,_||_| |_||_|\_\|___/ \___||_| |_|| .__/ \__|(_)\___/ |_| \__, |
|_| |_| |___/
RunAsTask() - Auto-elevates script without UAC prompt | http://ahkscript.org/boards/viewtopic.php?t=4334
_________________________________________________________________________________________________________
*/
RunAsTask() { ; By SKAN, http://goo.gl/yG6A1F, CD:19/Aug/2014 | MD:22/Jul/2023
Local CmdLine, TaskName, TaskExists, XML, TaskSchd, TaskRoot, RunAsTask
Local TASK_CREATE := 0x2, TASK_LOGON_INTERACTIVE_TOKEN := 3
Try TaskSchd := ComObjCreate( "Schedule.Service" ), TaskSchd.Connect()
, TaskRoot := TaskSchd.GetFolder( "\" )
Catch
Return "", ErrorLevel := 1
CmdLine := ( A_IsCompiled ? "" : """" A_AhkPath " """ ) . ( """" A_ScriptFullpath """" )
TaskName := "[RunAsTask] " A_ScriptName " @" SubStr( "000000000" DllCall( "NTDLL\RtlComputeCrc32"
, "Int",0, "WStr",CmdLine, "UInt",StrLen( CmdLine ) * 2, "UInt" ), -9 )
Try RunAsTask := TaskRoot.GetTask( TaskName )
TaskExists := ! A_LastError
If ( not A_IsAdmin and TaskExists ) {
RunAsTask.Run( "" )
ExitApp
}
If ( not A_IsAdmin and not TaskExists ) {
Run *RunAs %CmdLine%, %A_ScriptDir%, UseErrorLevel
ExitApp
}
If ( A_IsAdmin and not TaskExists ) {
XML := "
( LTrim Join
<?xml version=""1.0"" ?><Task xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task""><Regi
strationInfo /><Triggers /><Principals><Principal id=""Author""><LogonType>InteractiveToken</LogonT
ype><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><MultipleInstancesPolic
y>Parallel</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><
StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAva
ilable><IdleSettings><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleS
ettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><
RunOnlyIfIdle>false</RunOnlyIfIdle><DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteApp
Session><UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine><WakeToRun>false</WakeToRun><
ExecutionTimeLimit>PT0S</ExecutionTimeLimit></Settings><Actions Context=""Author""><Exec>
<Command>""" ( A_IsCompiled ? A_ScriptFullpath : A_AhkPath ) """</Command>
<Arguments>" ( !A_IsCompiled ? """" A_ScriptFullpath """" : "" ) "</Arguments>
<WorkingDirectory>" A_ScriptDir "</WorkingDirectory></Exec></Actions></Task>
)"
TaskRoot.RegisterTask( TaskName, XML, TASK_CREATE, "", "", TASK_LOGON_INTERACTIVE_TOKEN )
}
Return TaskName, ErrorLevel := 0
} ; _____________________________________________________________________________________________________
Usage example:
Code: Select all
#NoTrayIcon
RunAsTask() ; self elevate
Run RegEdit.exe
For subsequent runs, it will start a parallel elevated instance via Task scheduler and original instance will exit.
*UAC will prompt on the first run.
RunAsTask() generates a unique Taskname , for a given script as in following pattern:
"[RunAsTask]" . A_Space . A_ScriptName . A_Space . "@" . ( CRC32 hash of file paths, as decimal )
eg. [RunAsTask] My Admin Script.ahk @0123456789
For every change in A_ScriptFullpath ( compiled / uncompiled ) or A_AhkPath + A_ScriptFullpath ( uncompiled ), a new task will be registered. It is up to the user to clean and maintain the task scheduler.
Here is a task scheduler export of XML which was registered by RunAsTask(). The items in red are not in script. Items in blue are variable.
Task scheduler XML export
Edit1: 2014/Aug/22 13:25 UTCRunAsTask_CreateShortcut()
RunAsTask_CreateShortcut() is a supplementary function for RunAsTask(). It will create a shortcut for the Taskname returned by RunAsTask()
Shortcut target example: C:\Windows\system32\schtasks.exe /run /tn "[RunAsTask] MyAdminScript.ahk @3264355656"
Code: Select all
RunAsTask_CreateShortcut( TaskName := "", Folder := "", ShcName := "" ) { ; by SKAN, http://goo.gl/yG6A1F
Local LINK, Description
IfEqual, TaskName,, Return
LINK := ( FileExist( Folder ) ? Folder : A_ScriptDir ) "\" ( ShcName ? ShcName : A_ScriptName ) ".lnk"
FileGetShortcut, %LINK%,,,, Description
If ( Description <> Taskname )
FileCreateShortcut, schtasks.exe, %LINK%, %A_WorkingDir%,/run /tn "%TaskName%", %TaskName%,,,, 7
}
Code: Select all
TaskName := RunAsTask()
RunAsTask_CreateShortcut( TaskName ) ; Places a shortcut in Script folder
Code: Select all
RunAsTask_CreateShortcut( TaskName, A_Desktop ) ; Shortcut on desktop
RunAsTask_CreateShortcut( Taskname, A_Startup, "My Admin Script" ) ; Place in Startup. Force link name to avoid multiple startup entries.