Programmatically elevate a .NET application on any platform

macOS elevated permissions prompt

There are times when your .NET program needs to perform an operation that requires administrative rights (elevated privileges). An example could be modifying the hosts file (C:\Windows\System32\drivers\etc\hosts on Windows or /etc/hosts on Linux and macOS).

Technically, it’s not possible to “elevate the current process”. In reality, the only thing we can do is to start a new process with administrative rights. In this article, we will explore how to do this with a console application – while obtaining the user’s consent – on any platform.

Different ways to elevate a process depending on the platform

On Windows, starting a process with administrative rights involves using the User Account Control (UAC). The user is prompted to accept the elevation of privileges with a popup that should be familiar:

Windows UAC prompt

On Linux, it involves asking the user to enter their password to execute a command with sudo. Of course, the user must be among the sudoers.

Linux sudo password prompt

On macOS, it’s different again. You need to ask the user to enter their password, but this time using osascript, which will display a popup familiar to macOS users:

macOS elevated permission prompt

Detecting if the application is already elevated or not

Before elevating the current process, it’s interesting to check if the application is already elevated. Here is a cross-platform method to verify this:

I’ve included references to the .NET sources that inspired this method as comments.

Starting an elevated process

For the current process to start a new instance of itself with administrative rights, it needs to know where its executable is located. This can be more or less complicated depending on the platform, whether the program is executed from an executable file or a DLL (with dotnet run or from an IDE).

In the most common scenario where the program is always compiled into an executable file thanks to the MSBuild UseAppHost property (which is true by default), it is possible to retrieve the path of the current executable with Environment.ProcessPath.

Then, we can start a new process with administrative rights using the Process.Start method:

Let’s analyze the code method by method. CreateProcessStartInfo creates an instance of ProcessStartInfo and delegates configuration to platform-specific methods.

On Windows, it is easily possible to start a process with administrative rights using the Verb property of ProcessStartInfo with the value runas. There are several examples in the .NET source code, and the equivalent exists in PowerShell.

On Linux, simply make sudo the main command to execute and provide the rest as arguments.

On macOSosascript is used to run a script that asks the user to enter their password to obtain administrative rights. The problem that may arise here is that the arguments, unlike the Windows and Linux methods, are not escaped. If you use arguments that contain spaces, you will need to escape them, while keeping the script valid.

Finally, we start the process and wait for it to finish.

If you need to create a communication channel between the two processes, you can use named pipes or TCP sockets.

Leave a Reply