Vista setuid – How to elevate without prompting

Ever since Vista came out, users have been trying to find ways to avoid the “Elevation Prompt” when running things which require administrative access. There are lots of obvious solutions, but I’ve found one that’s not so obvious, and I’ve found an easy way to use it with PowerShell. First though, an explanation of what this is, and some of the “obvious” solutions.

UAC overview (feel free to skip this)

User Account Control (UAC) is a mechanism in Vista which finally brings Windows into the world of restricted user accounts that OS X and Unix/Linux have been in for years. Essentially it’s a mechanism which protects certain areas of the operating system from being changed (or even accessed) by users who don’t have administration rights. You can disable UAC completely, but it’s highly unrecommended — it’s basically like making all of your users into “root” level administrators, and it’s obviously overkill if all you want is for your administrator accounts to get prompted less.

There are several things you can do to leave the UAC mechanism in place while reducing the annoyance for users: they are all present as settings in the Local Security Policy snapin (secpol.msc) which controls the behavior of UAC and it’s elevation prompt. You can choose to require explicit login for everyone (a good idea for the family computer if you all share a single account) or to simply “Prompt for consent” for certain administrators, or even to Elevate without prompting which is basically like having all your administrators running as root (this is a logical idea only if you don’t normally log in as an administrator: it lets you have no prompting when you’re running as an administrator). Finally, you can tweak the behavior of the elevation prompt by disabling the “secure desktop,” this doesn’t get rid of the prompts, it just makes them a little less disruptive.

So far, this is all very much like a Mac or Linux system: with the exception that unlike OS X and Linux, Vista doesn’t just run the apps and let them fail with cryptic errors if they need administrative rights: it detects the attempt to access things which require administrative privileges and proactively prompts you to elevate them. Of course, there is another difference: most Windows apps aren’t written with this in mind: they insist on installing into the global “Program Files” folder instead of into the per-user apps folder (C:\Users\Name\AppData\Local\Apps\), and on accessing the registry, etc. This will change with time, but there will always be apps which need administrative access to install, and some which are actually for administering your system and will therefore always require administrative rights.

What about SetUID?

The problem is that the one thing Linux and OS X have that seems missing in Vista is the “setuid” feature: this allows you to specify that specific application always run with the rights of a specific user. The idea is that you control access to the specific file, but you set it to run as an administrator. This way “any” user who can access the app can run it without needing to have access to an administrator account. It allows you to give users access to some administration tools without giving them access to all of them.

It turns out that Vista has a feature like this hidden in the Task Scheduler. It’s not quite the same as setuid, you can’t use it to allow users to run interactive applications as other users, but it will allow you as a member of the administrator group to create tasks that run with “Highest Privileges” (that is: “Elevated”, or “as administrator”) without needing to deal with the elevation prompt each time. This solution is ideal for those tasks which you use repeatedly and which always require admin rights — but probably shouldn’t be used if non-administrators might use your account, and it can be scripted using PowerShell.

The Task Scheduler is a Management Console snapin, which means that it requires administrative access to run — but the tasks you create can be run based on schedules, events, or even manually via the SchTasks.exe application — which does not require admin rights (unless it’s modifying tasks).

Creating Tasks

Elevated Task Dialog

When you create a new Task (notice that the action is not “Create Scheduled Task”?) you can check off a box to “Run with highest privileges.” You can optionally set up a schedule, or triggers (e.g: you can set an app to run “At log on” to start an app automatically without an elevation prompt). On the Actions tab, simply specify the application you want to run, and then on the Settings tab make sure that the “Allow task to be run on demand” setting is checked off. You will probably also want to verify the setting for “if the task is already running” depending on the app.

Elevated Task Settings

Executing named tasks

Once a task has been created, you can run it by name using the command SchTasks.exe /Run /TN "The Name You Gave It" but you can’t pass any additional parameters. You can also create shortcuts to these commands (although you’ll have to manually set the shortcut’s icon.

Enter PowerShell

If all of this seems like a lot of work, you can automate the process. Once a task has been created, you can export it to XML and edit it before re-importing it … or adding it to multiple PCs. You can even create tasks from the commandline, but SchTasks doesn’t have a command line parameter which supports creating tasks without a schedule, so the only way around it is to use SchTasks with an XML file. If you have Windows PowerShell, it’s perfectly suited to creating these XML files on the fly:


# New-ElevatedTask.ps1
# <summary>Creates a new "On Demand Only" scheduled task to run an "Elevated" application on Vista</summary>
# <remarks>This MUST be run from an elevated prompt, so by default it just uses the current user ID</remarks>
param(
    $application
  , $arguments = ""
  , $startIn = $(Split-Path $application)
  , $friendlyName = $(Split-Path $application -leaf)
  , $taskname = $("Elevated $friendlyName")
  )
$xml = @"
<?xml version="
1.0" encoding="UTF-16"?>
<Task version="
1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
... abbreviated for display, create your own XML, or download the attachment ...
  <Actions Context="
Author">
    <Exec>
      <Command>{0}</Command>
      <Arguments>{1}</Arguments>
      <WorkingDirectory>{2}</WorkingDirectory>
    </Exec>
  </Actions>
</Task>
"
@

$xFile = "$([IO.Path]::GetTempFileName())"  # get a temporary file to put the xml in, then user the -f(ormat) command to do that
$xml -f  $application, $arguments, $startin | set-content $xFile
schtasks.exe /Create /XML $xFile /TN $taskname
 

Basically, you just wrap the XML that you exported into a powershell script and replace the interesting bits with script parameters. Since Schtasks must be run elevated to be able to create tasks, you need to run this script in an elevated powershell console — or modify the script to run schtasks.exe via runas or my vista sudo which is what I do, so it works regardless.

You can download the full New-ElevatedTask PowerShell script and try it out. It’s not well documented, I’m afraid, but it does have additional support for specifying an alternate user name and password, even though those don’t seem to work interactively (ie: you should only use alternate credentials for non-interactive apps like scripts or services).

Future Work

This New-ElevatedTask script will probably show up in the next release of PowerShell Community Extensions with a few enhancements, including the capability to automatically create shortcuts for you with their icon set properly. I have a couple of other ideas around it as well, but that’s pretty much the whole package (unless someone can explain a way to get apps run with embedded credentials to show up in the desktop session). Hypothetically you could create a promptless sudo for PowerShell using this mechanism, but I think it’s probably as big a risk as just turning off the elevation prompt. Basically, you could create a sudo.exe like the one I mentioned earlier but which looks in environment variables for the command and parameters to run if none is specified on the command line — then you can register it as an elevated task, and write a function to set the variables and execute the task:


function sudo([string]$command, [string]$parameters){
  set-content Env:\SudoCommand $command
  set-content Env:\SudoParameters $parameters
  schtasks.exe /run /TN "Elevated Sudo.exe"
}
 

Similar Posts: