Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Run as standard (limited) user


  • Please log in to reply
36 replies to this topic
ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
After reading the "Run as Administrator (XP/Vista/7) A_IsAdmin Params [Lib]", i came up with a solution for the inverse case: run a process as a limited user.

This is useful if we need to start another script or an external program from an elevated context. I used the CreateRestrictedToken winapi function, but the implementation is very basic. It seems to work with classic Autohotkey, i didn't check it with AHK_L.

Please share thoughts and suggestions.

#SingleInstance force

RunAsAdmin()

hModule := DllCall("Kernel32.dll\LoadLibrary", Str, "Advapi32.dll", "UInt")

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Opens current process and gets the token
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; OpenProcess - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320.aspx
; PROCESS_QUERY_INFORMATION = 0x0400
hProcess := DllCall(	"Kernel32.dll\OpenProcess"
						, UInt, 0x0400
						, Int, 0
						, UInt, DllCall("Kernel32.dll\GetCurrentProcessId")
						, "UInt")

; OpenProcessToken - http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295.aspx
; TOKEN_ASSIGN_PRIMARY = 0x0001
; TOKEN_DUPLICATE = 0x0002
; TOKEN_QUERY = 0x0008
; TOKEN_ADJUST_DEFAULT = 0x0080;
DllCall(	"Advapi32.dll\OpenProcessToken"
			, UInt, hProcess
			, UInt, 0x0001 | 0x0002 | 0x0008 | 0x0080
			, UIntP, hToken)

if A_OSVersion in WIN_2000,WIN_XP		; The flag LUA_TOKEN doesn't work on XP, then we need to deny the Administrators SID
{
	oldSys = 1
	
	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	; Creates an Administrators SID and fills SID structure
	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	; GetSidLengthRequired - http://msdn.microsoft.com/en-us/library/windows/desktop/aa446656.aspx
	; *** [IMPORTANT]
	; *** The Well-Known Administrators SID needs 2 subauthorities: 
	; *** SECURITY_BUILTIN_DOMAIN_RID and DOMAIN_ALIAS_RID_ADMINS
	; *** http://msdn.microsoft.com/en-us/library/windows/desktop/aa379597.aspx
	sidSize := DllCall(		"Advapi32.dll\GetSidLengthRequired"
							, UChar, 2
							, "UInt")

	VarSetCapacity(pAdminSid, sidSize, 0)

	; CreateWellKnownSid - http://msdn.microsoft.com/en-us/library/windows/desktop/aa446585.aspx
	; Well-Known SID Structures - http://msdn.microsoft.com/en-us/library/cc980032.aspx
	; WELL_KNOWN_SID_TYPE { ... WinBuiltinAdministratorsSid = 26 ...}
	DllCall(	"Advapi32.dll\CreateWellKnownSid"
				, UInt, 26
				, UInt, 0
				, UInt, &pAdminSid
				, UIntP, sidSize)

	; SID_AND_ATTRIBUTES - http://msdn.microsoft.com/en-us/library/aa379595
	VarSetCapacity(sAdminSidAttr, 8, 0)		; Assuming 32bit pointer size
	NumPut(&pAdminSid, sAdminSidAttr, 0, "UInt")
}

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Restricts the token (denies the Administrators SID on XP)
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; CreateRestrictedToken - http://msdn.microsoft.com/en-us/library/Aa446583
; DISABLE_MAX_PRIVILEGE = 0x1
; LUA_TOKEN = 0x4
DllCall(	"Advapi32.dll\CreateRestrictedToken"
			, UInt, hToken
			, UInt, oldSys ? 0x1 : 0x4
			, UInt, oldSys ? 1 : 0
			, UInt, oldSys ? &sAdminSidAttr : 0
			, UInt, 0
			, UInt, 0
			, UInt, 0
			, UInt, 0
			, UIntP, hResToken)

if A_OSVersion in WIN_VISTA		; We can set integrity levels only on Windows Vista/7
{
	newSys = 1
	
	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	; Creates an integrity SID and sets the integrity level
	; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	; *** [IMPORTANT]
	; *** The Well-Known Integrity SIDs need 1 subauthority: 
	; *** In our case, we need SECURITY_MANDATORY_LOW_RID or SECURITY_MANDATORY_MEDIUM_RID.
	; *** http://msdn.microsoft.com/en-us/library/bb625963.aspx
		
	; GetSidLengthRequired - http://msdn.microsoft.com/en-us/library/windows/desktop/aa446656.aspx
	sidSize := DllCall(		"Advapi32.dll\GetSidLengthRequired"
							, UChar, 1
							, "UInt")

	VarSetCapacity(pIntegritySid, sidSize, 0)
		
	; CreateWellKnownSid - http://msdn.microsoft.com/en-us/library/windows/desktop/aa446585.aspx
	; Well-Known SID Structures - http://msdn.microsoft.com/en-us/library/cc980032.aspx
	; WELL_KNOWN_SID_TYPE { ... WinLowLabelSid = 66, WinMediumLabelSid = 67 ...}
	DllCall(	"Advapi32.dll\CreateWellKnownSid"
				, UInt, 67
				, UInt, 0
				, UInt, &pIntegritySid
				, UIntP, sidSize)

	; SID_AND_ATTRIBUTES - http://msdn.microsoft.com/en-us/library/aa379595
	; SE_GROUP_INTEGRITY = 0x00000020L
	VarSetCapacity(sIntegritySidAttr, 8, 0)		; Assuming 32bit pointer size
	NumPut(&pIntegritySid, sIntegritySidAttr, 0, "UInt")
	NumPut(0x00000020L, sIntegritySidAttr, 4, "UInt")
		
	; *** [IMPORTANT]
	; *** SetTokenInformation's 3rd parameter is the TOKEN_MANDATORY_LABEL structure, but,
	; *** if we encapsulate the sIntegritySidAttr inside it (as written in Windows docs),
	; *** the function returns a 1337 error (ERROR_INVALID_SID).
	; *** http://msdn.microsoft.com/en-us/library/windows/desktop/bb394727.aspx
		
	; SetTokenInformation - http://msdn.microsoft.com/en-us/library/windows/desktop/aa379591.aspx
	; TOKEN_INFORMATION_CLASS = {... TokenIntegrityLevel = 25 ...}
	DllCall(	"Advapi32.dll\SetTokenInformation"
				, UInt, hResToken
				, UInt, 25
				, UInt, &sIntegritySidAttr
				, UInt, NumGet(sidSize, 0, "UInt") + 8)
}

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Starts the process with the restricted token
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
; STARTUPINFO - http://msdn.microsoft.com/en-us/library/ms686331
VarSetCapacity(sStartInfo, 68, 0)		; Assuming 32bit pointer size
NumPut(68, sStartInfo, 0, "UInt")
NumPut("winsta0\\default", sStartInfo, 8, "Str")
	
; PROCESS_INFORMATION - http://msdn.microsoft.com/en-us/library/ms684873
VarSetCapacity(sProcInfo, 16, 0)		; Assuming 32bit pointer size

; CreateProcessAsUser - http://msdn.microsoft.com/en-us/library/ms682429
; NORMAL_PRIORITY_CLASS = 0x00000020
DllCall(	"Advapi32.dll\CreateProcessAsUserA"
			, UInt, hResToken
			, Int, "NULL"
			, Str, "C:\\Windows\\System32\\cmd.exe"
			, UInt, 0
			, UInt, 0
			, Int, 0
			, UInt, 0x00000020
			, UInt, 0
			, Int, "NULL"
			, UInt, &sStartInfo
			, UInt, &sProcInfo)

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Closes handles and frees libraries and structures
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DllCall("Kernel32.dll\CloseHandle", UInt, hProcess)
DllCall("Kernel32.dll\CloseHandle", UInt, hToken)
DllCall("Kernel32.dll\CloseHandle", UInt, hResToken)
DllCall("Kernel32.dll\CloseHandle", UInt, NumGet(sProcInfo, 0, "UInt"))
DllCall("Kernel32.dll\CloseHandle", UInt, NumGet(sProcInfo, 4, "UInt"))
if oldSys 
{
	DllCall("Advapi32.dll\FreeSid", UInt, &pAdminSid)
}
if newSys
{
	DllCall("Advapi32.dll\FreeSid", UInt, &pIntegritySid)
}
DllCall("Kernel32.dll\FreeLibrary", UInt, hModule)

; RunAsAdmin - Thanks to shajul (http://www.autohotkey.com/forum/viewtopic.php?t=50448)
RunAsAdmin() {
	global
	Loop, %0%  ; For each parameter:
		params .= A_Space . %A_Index%
	local ShellExecute
	ShellExecute := A_IsUnicode ? "shell32\ShellExecute":"shell32\ShellExecuteA"
	if not A_IsAdmin
	{
		A_IsCompiled
		? DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_ScriptFullPath, str, params , str, A_WorkingDir, int, 1)
		: DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_AhkPath, str, """" . A_ScriptFullPath . """" . A_Space . params, str, A_WorkingDir, int, 1)
		ExitApp
	}
}


Changelog:
1 nov 2011 - Fixed Windows XP problems, added integrity level management for Windows Vista/7.
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Very nice. I had used something similar but from a custom C++ dll before. When I'll integrate this I'll make sure to post a Unicode/x64 version.

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
Thanks fragman.

I forgot to say that i tested this on Windows 7 and it seems to work well, but the Integrity Level was not lowered. If you launch it from an elevated context, the IL is still high...
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

xxOrpheus
  • Members
  • 134 posts
  • Last active: Jul 21 2014 12:15 AM
  • Joined: 27 Sep 2011
This is cool :) Good job.

MeNoGuest
  • Guests
  • Last active:
  • Joined: --
Thanks! I have numerous uses for this (mostly roll-your-own installers), and it will surely come in handy :)

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
Thanx bros!

Updates:

I tested this on XP, and it doesn't work on it. It works well on Vista + 7 until the LUA_TOKEN = 0x4 flag is used in CreateRestrictedToken. To make it work in XP, i think that the administrative SID must be disabled when calling CreateRestrictedToken.

Also, as i said before, in Vista and 7, the process will be launched with the same integrity level of the parent. Since it will be almost surely started elevated, the child process will get high integrity.


Requests:

If there's someone skilled with the process creation Windows api that can help with the problem described above, i'll be glad to receive any advice!
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I tried writing a generic version now (that makes use of _Struct library -> requires AHK_L), but it doesn't work yet, gives me ERROR_PATH_NOT_FOUND. Any ideas?

RunAsUser(Command, WorkingDirectory)
{
	static STARTUPINFO := "DWORD cb,LPTSTR lpReserved,LPTSTR lpDesktop,LPTSTR lpTitle,DWORD dwX,DWORD dwY,DWORD dwXSize,DWORD dwYSize,DWORD dwXCountChars,DWORD dwYCountChars,DWORD dwFillAttribute,DWORD dwFlags,WORD wShowWindow,WORD cbReserved2,LPBYTE lpReserved2,HANDLE hStdInput,HANDLE hStdOutput,HANDLE hStdError"
	static PROCESS_INFORMATION := "HANDLE hProcess, HANDLE hThread, DWORD dwProcessId, DWORD dwThreadId"
	hModule := DllCall("LoadLibrary", Str, "Advapi32.dll") 
	
	; OpenProcess - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx 
	; PROCESS_QUERY_INFORMATION = 0x0400 
	hProcess := DllCall(   "Kernel32.dll\OpenProcess", UInt, 0x0400, Int, 0, UInt, DllCall("Kernel32.dll\GetCurrentProcessId"), "Ptr") 
	
	; OpenProcessToken - http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx 
	; TOKEN_ASSIGN_PRIMARY = 0x0001 
	; TOKEN_DUPLICATE = 0x0002 
	; TOKEN_QUERY = 0x0008 
	DllCall(   "Advapi32.dll\OpenProcessToken", Ptr, hProcess, UInt, 0x0001 | 0x0002 | 0x0008, PtrP, hToken) 
	
	; CreateRestrictedToken - http://msdn.microsoft.com/en-us/library/Aa446583 
	; LUA_TOKEN = 0x4 
	DllCall(   "Advapi32.dll\CreateRestrictedToken", Ptr, hToken, UInt, 0x4, UInt, 0, Ptr, 0, UInt, 0, Ptr, 0, UInt, 0, Ptr, 0, PtrP, hResToken) 
	
	
	; Assuming 32bit pointer size 
	;~ VarSetCapacity(sInfo, 68, 0) 
	;~ VarSetCapacity(pInfo, 16, 0) 
	
	sInfo := new _Struct(STARTUPINFO)
	sInfo.cb := sizeof(STARTUPINFO)
	sInfo.lpDesktop := "winsta0\default"
	pInfo := new _Struct(PROCESS_INFORMATION)
	;~ NumPut(68, sInfo, 0, "UInt") 
	;~ NumPut("winsta0\\default", sInfo, 8, "Str") 
	
	; CreateProcessAsUser - http://msdn.microsoft.com/en-us/library/ms682429 
	; NORMAL_PRIORITY_CLASS = 0x00000020 
	result := DllCall(   "Advapi32.dll\CreateProcessAsUser" , Ptr, hResToken, PtrP, 0, Str, Command, Ptr, 0, Ptr, 0, Int, 0, UInt, 0x00000020, Ptr, 0, Str, WorkingDirectory ? WorkingDirectory : A_ScriptDir, PtrP, sInfo, PtrP, pInfo)
	MsgBox % "result: " result "`nLast error:" A_LastError "`nCommand: " Command "`nWorking directory: " WorkingDirectory
	DllCall("CloseHandle", PTR, hProcess)
	DllCall("CloseHandle", PTR, hToken)
	DllCall("CloseHandle", PTR, sInfo.hStdInput)
	DllCall("CloseHandle", PTR, sInfo.hStdOutput)
	DllCall("CloseHandle", PTR, sInfo.hStdError)
	DllCall("CloseHandle", PTR, pInfo.hProcess)
	DllCall("CloseHandle", PTR, pInfo.hThread)
	return pInfo.dwProcessId
}

As a correction to the code in the original post, the handles need to be closed according to MSDN. One more question, what would happen if the user was an admin (UAC disabled)? Personally I would rather want to run as admin just like the user when UAC is disabled. I guess I could fake that though by checking the UAC level and simply using run if required.

That said, I think it would be nice if these features would be integrated in AHK since it is a relatively common issue.

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
About the ERROR_PATH_NOT_FOUND, have you tried to escape the path? I mean something like C:\\somedir\\somesubdir\\program.exe.

If it doesn't work you can try to ditch the _Struct library and return to the varsetcapacity/numput approach.

About the handles, you're right, they must be closed.

About the UAC question: starting a program with a restricted token has sense if you ARE admin. If UAC is disabled, this approach has more sense because normally your programs always start elevated and you can use it to restrict them.

If you start this script with UAC enabled and from a non-elevated context, you create a restricted token from an already restricted process (because of UAC).

Then to correctly test the behaviour of this program with UAC enabled you have to start Autohotkey as admin or use this code (found here: <!-- m -->http://www.autohotke...pic.php?t=50448<!-- m -->) to trigger the elevation:

RunAsAdmin()

; do something as administrator (if you want)

; insert the "run as user" code here and do something as user


RunAsAdmin() {
global
Loop, %0%  ; For each parameter:
    params .= A_Space . %A_Index%
local ShellExecute
ShellExecute := A_IsUnicode ? "shell32\ShellExecute":"shell32\ShellExecuteA"
if not A_IsAdmin
    {
      A_IsCompiled
        ? DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_ScriptFullPath, str, params , str, A_WorkingDir, int, 1)
        : DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_AhkPath, str, """" . A_ScriptFullPath . """" . A_Space . params, str, A_WorkingDir, int, 1)
      ExitApp
    }
}

All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
Uhm, maybe ERROR_PATH_NOT_FOUND is relative to the second parameter you used on CreateProcessAsUser. You passed an address instead of the pointer itself. Try with Ptr instead of PtrP.
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008
I found how to make this to work in Windows XP and eventually fix the integrity level issue.

I'll update the code soon.


EDIT >> 1 nov 2011:

New code. Sorry for over-commenting my code, but without those info i can't remember what i did :D
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Escaping backlashes is not needed in AHK since they aren't escape characters themselves in AHK (except regex).

PtrP is used since MSDN says that the string is in/out so it might be modified. Using a normal PTR doesn't work and gives a DllCall error. Using Str, "" does but I'm not sure if it's the same on Unicode builds.

My AHK program is running elevated, but it should be able to start programs like they would if the user launched them through explorer (that is, non-admin with UAC on, Admin with UAC off). This is important because of things like mounted net drives not being available to elevated processes when they were mounted with restricted permissions.

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008

Escaping backlashes is not needed in AHK since they aren't escape characters themselves in AHK (except regex).

PtrP is used since MSDN says that the string is in/out so it might be modified. Using a normal PTR doesn't work and gives a DllCall error. Using Str, "" does but I'm not sure if it's the same on Unicode builds.


Uhm no, the second parameter it's __in_opt, not __inout. You need to pass a NULL value, i don't know if Str, "" is correct.

I think that the correct way is Ptr, 0 or Str, 0. Searching the forum i found few people using Int, "NULL" (and it worked for me).

My AHK program is running elevated, but it should be able to start programs like they would if the user launched them through explorer (that is, non-admin with UAC on, Admin with UAC off). This is important because of things like mounted net drives not being available to elevated processes when they were mounted with restricted permissions.


From my test the process is started in both cases but i find no sense on restricting an already restricted token (unless you need to drop some privileges).

However, maybe i don't get it. Maybe there's some relation between UAC and the restricted token flag. Can you tell me an accurate use case that i can replicate?
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
You're right, however the DllCall only works with PtrP, 0 and Str, "" as second parameter, while the third accepts Ptr as well. Maybe because 2nd parameter is constant?
You can try mounting a network share as drive on windows startup and check FileExist() in AHK, one time running elevated, one time non-elevated. I think the elevated one won't be able to see it. I had some issues with this earlier on, that's mostly why I'm looking for a RunAsUser function.

I also did some reading since my last post and found some alternative approaches:

1)Get an explorer COM interface and use ShellExecute. This is rather limited I think.
2)Create a scheduled task through COM with low privileges.
3)Keep a non-elevated script running and have it execute programs through windows messages or similar methods.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Edit: I could not get this to work yet, but I've implemented the method that makes use of task scheduler:
RunAsUser(Target, Arguments, WorkingDirectory)
{
	static TASK_TRIGGER_REGISTRATION := 7   ; trigger on registration. 
	static TASK_ACTION_EXEC := 0  ; specifies an executable action. 
	static TASK_CREATE := 2
	static TASK_RUNLEVEL_LUA := 0
	static TASK_LOGON_INTERACTIVE_TOKEN := 3
	objService := ComObjCreate("Schedule.Service") 
	objService.Connect() 

	objFolder := objService.GetFolder("\") 
	objTaskDefinition := objService.NewTask(0) 

	principal := objTaskDefinition.Principal 
	principal.LogonType := TASK_LOGON_INTERACTIVE_TOKEN    ; Set the logon type to TASK_LOGON_PASSWORD 
	principal.RunLevel := TASK_RUNLEVEL_LUA  ; Tasks will be run with the least privileges. 

	colTasks := objTaskDefinition.Triggers
	objTrigger := colTasks.Create(TASK_TRIGGER_REGISTRATION) 
	endTime += 1, Minutes  ;end time = 1 minutes from now 
	FormatTime,endTime,%endTime%,yyyy-MM-ddTHH`:mm`:ss
	objTrigger.EndBoundary := endTime
	colActions := objTaskDefinition.Actions 
	objAction := colActions.Create(TASK_ACTION_EXEC) 
	objAction.ID := "7plus run" 
	objAction.Path := Target
	objAction.Arguments := Arguments
	objAction.WorkingDirectory := WorkingDirectory ? WorkingDirectory : A_WorkingDir
	objInfo := objTaskDefinition.RegistrationInfo
	objInfo.Author := "7plus" 
	objInfo.Description := "Runs a program as non-elevated user" 
	objSettings := objTaskDefinition.Settings 
	objSettings.Enabled := True 
	objSettings.Hidden := False 
	objSettings.DeleteExpiredTaskAfter := "PT0S"
	objSettings.StartWhenAvailable := True 
	objSettings.ExecutionTimeLimit := "PT0S"
	objSettings.DisallowStartIfOnBatteries := False
	objSettings.StopIfGoingOnBatteries := False
	objFolder.RegisterTaskDefinition("", objTaskDefinition, TASK_CREATE , "", "", TASK_LOGON_INTERACTIVE_TOKEN ) 
}
Make sure to remove the 7plus references ;)

The only weird thing here is that cmd.exe will show taskeng.exe in its title which might be a bit strange for users. Any ideas how to avoid this?

ABCza
  • Members
  • 132 posts
  • Last active: Jan 04 2015 01:02 AM
  • Joined: 03 Jun 2008

The only weird thing here is that cmd.exe will show taskeng.exe in its title which might be a bit strange for users. Any ideas how to avoid this?


Yes: <!-- m -->http://www.autohotke...WinSetTitle.htm<!-- m -->

I find the approaches you listed before a little "alien" in relation to the required result. I think that using the winapi is more "consistent". What i want to say is that there's no need to search for hackish ways when there's a (relatively) easy and established way to do something.

However i understood your problem and i found an explanation for it with a registry workaround: <!-- m -->http://support.microsoft.com/kb/937624<!-- m -->

Could you explain me the behaviour that you are trying to achieve? What your application is expected to do? It will be used in a multi-user environment?
All my scripts/snippets are released under the WTFPL: http://sam.zoy.org/wtfpl/COPYING