Expert Texture Home Contact me About Subscribe Digipede Connect on LinkedIn rwandering on Twitter rwandering on FriendFeed

rwandering.net

The blogged wandering of Robert W. Anderson

Unprivileged Tasks in Windows 6 with VBS

Last week, Bart de Smet wrote about calling the Task Scheduler in Windows Vista (and Windows Server 2008) from managed code.  In his usual style, he does a great job diving into the topic.

It reminded me of something I did last year for Windows Server 2008 Certification: write code to start an unprivileged task in Windows 6 specifically written for installers.   

If you are familiar with UAC, you know that applications identify their least required privilege level in their manifest.  Applications that don’t require elevation identify themselves with the level="asInvoker" tag (the value may be confusing, but makes sense).

This creates a bit of complexity for installations that launch applications when they finish.  If your installation required elevation, but the launched application does not, what should you do?  Windows UAC guidelines say that you should launch them unprivileged.  This makes sense: you don’t want an application to run elevated as a side-effect of the installation.

And you do this by starting the task in the Windows 6 task scheduler.

The UAC guidelines contain some C++ code for this, and Bart has a managed version, but for reasons of maintainability and consistency, we wanted VB Script.  I was able to find some pieces of this online, but the following code is basically a port of the UAC Guidelines version with a check for Windows version too. 

' Arguments 
set args = WScript.Arguments 
if args.Count >= 1 then 
    strCommand = args(0) 
end if 
if args.Count >= 2 then 
    strArguments = args(1) 
end if 

' Determine the version of Windows 
set objWMI = GetObject("winmgmts:\\.\root\cimv2") 
set colOS = objWMI.InstancesOf("Win32_OperatingSystem") 
for each objOS in colOS 
   version = split(CStr(objOS.Version), ".", 2) 
next 

if CInt(version(0)) < 7 then 
    ' pre Vista / Server 2008.  Just run the task directly 
    set objShell = CreateObject("Wscript.Shell") 
    set objProc  = objShell.Exec(strCommand & " " & strArguments) 
else 
    ' Vista / Server 2008 or later.  Schedule it for immediate execution 
    scheduleTask strCommand, strArguments 
end if 

' Schedule a task for immediate execution; requires Windows 6 or later 
private sub ScheduleTask(strCommand, strArguments) 
    ' Some constants we need 
    TASK_TRIGGER_REGISTRATION = 7 
    TASK_ACTION_EXEC = 0 
    TASK_CREATE	= 2 
    TASK_LOGON_GROUP = 4 

    on error goto 0 
    ' Get the TaskService class 
    set pService = CreateObject("Schedule.Service") 

    ' Connect to the task service. 
    pService.Connect  

    '  Get pointer to root task folder. 
    set pRootFolder = pService.GetFolder("\") 

    Randomize(20000) 
    taskName = "MyBackgroundTask " & CStr(Rnd(1000)) 

    '  See if task exists, delete it if it does. 
    on error resume next 
    pRootFolder.DeleteTask taskName, 0 
    on error goto 0 

    '  Create task 
    set pTask = pService.NewTask(0) 
    set pSettings = pTask.Settings 
    pSettings.StopIfGoingOnBatteries = false 
    pSettings.DisallowStartIfOnBatteries = false 

    ' Create trigger 
    set triggerCollection = pTask.Triggers 
    set trigger = triggerCollection.Create(TASK_TRIGGER_REGISTRATION) 

    ' Create a new action 
    set actionCollection = pTask.Actions 
    set action = actionCollection.Create(TASK_ACTION_EXEC) 
    action.Path = strCommand 
    action.Arguments = strArguments 

    ' Register the task using users group 
    set registeredTask = pRootFolder.RegisterTaskDefinition(taskName, pTask, TASK_CREATE,  "S-1-5-32-545", null, TASK_LOGON_GROUP, "") 

    ' give 10 seconds for the task to start 
    for i = 0 to 100 
        state = registeredTask.State 
        if state = TASK_STATE_RUNNING then 
            break 
        end if 
        WScript.Sleep 100 
    next 

   ' delete the task 
    pRootFolder.DeleteTask taskName, 0 
end sub

You can see it takes arguments for the application and an argument to pass to the application.  Also note that the VBS must be run elevated in Windows 6, otherwise tasks cannot be scheduled.

Ah, VB Script.  You gotta love it.  Or not, but I wish someone else had posted this! 

Note to Microsoft: you would have saved a lot of people time if you had included a VBS version in your guidelines document.

[tags]VBS, UAC, Server 2008, Vista, Windows 6, Task Scheduler[/tags]

Tags: , , , , ,

    Trackback

2 Comments »