With going on stage Windows Vista and Windows 7 later on and new user security paradigm introduction (UAC), it becomes necessary to support such behavior when elevated privileges are required to perform some portion of code base, i.e., writing to registry, modifying files under system protected folders, etc.
So, in general, there are two ways to implement such behavior:
Usually the part of the program requires elevated privileges is a settings form which writes to Windows registry when the core functionality - don't.
Another case - a console application where core functionality requires elevated privileges and some helpers - such as help message displaying - don't.
Let's declare the skeleton of such console application.
Entry point method parses input command line arguments and branches the flow control relying on the parse results wrapped into an object:
static void Main(string[] args)
{
Core.Settings = ApplicationSettingsParser.Parse(args);
if (Core.Settings.UsageFlag || (args.Length == 0))
{
PrintUsage();
}
else if (!Core.Settings.EngageFlag)
{
var info = new ProcessStartInfo(
Assembly.GetEntryAssembly().Location,
String.Join(" ", Enumerable.Concat(args, new[] { "--engage" })))
{
Verb = "runas", };
var process = new Process
{
EnableRaisingEvents = true, StartInfo = info
};
process.Start();
process.WaitForExit(); }
else if (Core.Settings.EngageFlag)
{
Console.WriteLine("Elevated privileges gained={0}", Core.IsElevated);
}
}
Here's a method just displaying a sample help message:
private static void PrintUsage()
{
Console.WriteLine("Usage: ElevatedPrivilegesOnDemand.exe --do [--engage] | -?");
}
Parsing method is placed into a dedicated helper:
public static ApplicationSettings Parse(IEnumerable<string> args)
{
var settings = new ApplicationSettings();
foreach (var arg in args)
{
switch (arg)
{
case "-?":
{
return new ApplicationSettings() { UsageFlag = true };
}
case "--do":
{
settings.DoFlag = true;
break;
}
case "--engage":
{
settings.EngageFlag = true;
break;
}
}
}
return settings;
}
Which returns a POCO object keeping settings:
class ApplicationSettings
{
public ApplicationSettings()
{
}
public bool DoFlag { get; set; }
public bool EngageFlag { get; set; }
public bool UsageFlag { get; set; }
}
Internal singleton setting instance is attached to a pivot class. It also contains an addition helper method to check elevated privileges obtaining:
static class Core
{
public static bool IsElevated
{
get
{
return new WindowsPrincipal
(WindowsIdentity.GetCurrent()).IsInRole
(WindowsBuiltInRole.Administrator);
}
}
public static ApplicationSettings Settings { get; set; }
}
The executing flow is being separated to the two parts: in the first, it's being determined whenever elevated privileges are required relying on command line arguments specified or not. And if yes - an additional parameter is being added and passed to the same application but started with administrative rights and redirected console output.
And in the second, the core functionality is being executed with full privileges gained.
Now there is no needs to run the whole application under elevated privileges mode when it is not necessary.
Unfortunately, it seems that it's not possible to hide child process window and elevate its privileges in the same time:
ProcessStartInfo.Verb
will only have an effect if the process is started by ShellExecuteEx()
which requires UseShellExecute = true
- Redirecting I/O and hiding the window can only work if the process is started by
CreateProcess()
which requires UseShellExecute
I'm investigating this behavior and will update my article as far will find a solution to hide a window of started elevated process.
The reader can find the following links to be interesting:
Questions tagged UAC and manifest on Stack Overflow, especially this and related.
History
- 28/08/2010 - Version 1.0.1 - Initial release
- 29/08/2010 - Version 1.0.2 - Fix of example source code
- 30/08/2010 - Version 1.1.3 - Code change and remark addition considering hiding window of process started with elevated privileges