Introduction
User Account Control (UAC) is a new security component in Windows Vista and newer operating systems. With UAC fully enabled, interactive administrators normally run with least user privileges. This article and the attached code samples demonstrate these frequently asked coding scenarios related to UAC.
- How to check if the current process is running as administrator?
- How to know if the primary access token of the current process belongs to user account that is a member of the local Administrators group, even if it currently is not elevated?
- How to check if the current process is elevated? The elevation information is available to only Windows Vista and newer operating systems because there was no UAC and "elevation" before Windows Vista.
- How to get the integrity level of the current process (System/High/Medium/Low/Unknown)? The integrity level information is available to only Windows Vista and newer operating systems because there was no UAC and "integrity level" before Windows Vista.
- How to show a UAC shield icon on the UI for tasks that require elevation?
- How to self-elevate the current process?
- How to automatically elevate the process when it's started up?
We provide code samples to demonstrate the above how-to scenarios in three programming languages (native VC++, VC#, VB.NET) to meet the needs of different developers.
Language |
Sample |
VC++ |
CppUACSelfElevation |
VC# |
CSUACSelfElevation |
VB.NET |
VBUACSelfElevation |
The code samples are part of Microsoft All-In-One Code Framework, which is a centralized code sample solution from Microsoft. You can download the code from this CodeProject article and from the project's download page: http://1code.codeplex.com/releases/.
Background
Microsoft All-In-One Code Framework delineates the framework and skeleton of most Microsoft development techniques (e.g., COM, Data Access, IPC) using typical sample codes in different programming languages (e.g., Visual C#, VB.NET, Visual C++). Each sample is elaborately selected, composed, and documented to demonstrate one frequently-asked, tested or used coding scenario based on Microsoft's support experience in MSDN newsgroups and forums.
Demo
This is a quick demo of the attached UAC samples.
Step 1. After you successfully build the sample project in Visual Studio 2008, you will get an application depending on the programming language that you are using: CppUACSelfElevation.exe / CSUACSelfElevation.exe / VBUACSelfElevation.exe.
Step 2. Run the application as a protected administrator on a Windows Vista or Windows 7 system with UAC fully enabled. The application should display the following content on the main dialog. There is a UAC shield icon on the Self-elevate button.
Step 3. Click on the Self-elevate button. You will see a Consent UI.
Step 4. Click Yes to approve the elevation. The original application will then be started and display the following content on the main dialog.
The Self-elevate button on the dialog does not have the UAC shield icon this time. That is, the application is running as elevated administrator. The elevation succeeds. If you click on the Self-elevate button again, the application will tell you that it is running as administrator.
Step 5. Click OK to close the application.
Using the Code
The code introduced in this section is for VC++ developers only. You can find the VC# and VB.NET implementations in the CSUACSelfElevation
and VBUACSelfElevation
sample packages.
- How to check if the current process is running as administrator?
internal bool IsRunAsAdmin()
{
WindowsIdentity id = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(id);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
- How to know if the primary access token of the current process belongs to user account that is a member of the local Administrators group, even if it currently is not elevated?
internal bool IsUserInAdminGroup()
{
bool fInAdminGroup = false;
SafeTokenHandle hToken = null;
SafeTokenHandle hTokenToCheck = null;
IntPtr pElevationType = IntPtr.Zero;
IntPtr pLinkedToken = IntPtr.Zero;
int cbSize = 0;
try
{
if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle,
NativeMethod.TOKEN_QUERY | NativeMethod.TOKEN_DUPLICATE, out hToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (Environment.OSVersion.Version.Major >= 6)
{
cbSize = sizeof(TOKEN_ELEVATION_TYPE);
pElevationType = Marshal.AllocHGlobal(cbSize);
if (pElevationType == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!NativeMethod.GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType,
cbSize, out cbSize))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)
Marshal.ReadInt32(pElevationType);
if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
{
cbSize = IntPtr.Size;
pLinkedToken = Marshal.AllocHGlobal(cbSize);
if (pLinkedToken == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!NativeMethod.GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken,
cbSize, out cbSize))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken);
hTokenToCheck = new SafeTokenHandle(hLinkedToken);
}
}
if (hTokenToCheck == null)
{
if (!NativeMethod.DuplicateToken(hToken,
SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
out hTokenToCheck))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
WindowsIdentity id =
new WindowsIdentity(hTokenToCheck.DangerousGetHandle());
WindowsPrincipal principal = new WindowsPrincipal(id);
fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator);
}
finally
{
if (hToken != null)
{
hToken.Close();
hToken = null;
}
if (hTokenToCheck != null)
{
hTokenToCheck.Close();
hTokenToCheck = null;
}
if (pElevationType != IntPtr.Zero)
{
Marshal.FreeHGlobal(pElevationType);
pElevationType = IntPtr.Zero;
}
if (pLinkedToken != IntPtr.Zero)
{
Marshal.FreeHGlobal(pLinkedToken);
pLinkedToken = IntPtr.Zero;
}
}
return fInAdminGroup;
}
- How to check if the current process is elevated? The elevation information is available to only Windows Vista and newer operating systems because there was no UAC and "elevation" before Windows Vista.
internal bool IsProcessElevated()
{
bool fIsElevated = false;
SafeTokenHandle hToken = null;
int cbTokenElevation = 0;
IntPtr pTokenElevation = IntPtr.Zero;
try
{
if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle,
NativeMethod.TOKEN_QUERY, out hToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION));
pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation);
if (pTokenElevation == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!NativeMethod.GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation,
cbTokenElevation, out cbTokenElevation))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
TOKEN_ELEVATION elevation = (TOKEN_ELEVATION)Marshal.PtrToStructure(
pTokenElevation, typeof(TOKEN_ELEVATION));
fIsElevated = (elevation.TokenIsElevated != 0);
}
finally
{
if (hToken != null)
{
hToken.Close();
hToken = null;
}
if (pTokenElevation != IntPtr.Zero)
{
Marshal.FreeHGlobal(pTokenElevation);
pTokenElevation = IntPtr.Zero;
cbTokenElevation = 0;
}
}
return fIsElevated;
}
- How to get the integrity level of the current process (System/High/Medium/Low/Unknown)? The integrity level information is available to only Windows Vista and newer operating systems because there was no UAC and "integrity level" before Windows Vista.
internal int GetProcessIntegrityLevel()
{
int IL = -1;
SafeTokenHandle hToken = null;
int cbTokenIL = 0;
IntPtr pTokenIL = IntPtr.Zero;
try
{
if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle,
NativeMethod.TOKEN_QUERY, out hToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!NativeMethod.GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, IntPtr.Zero, 0,
out cbTokenIL))
{
int error = Marshal.GetLastWin32Error();
if (error != NativeMethod.ERROR_INSUFFICIENT_BUFFER)
{
throw new Win32Exception(error);
}
}
pTokenIL = Marshal.AllocHGlobal(cbTokenIL);
if (pTokenIL == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!NativeMethod.GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenIL, cbTokenIL,
out cbTokenIL))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
TOKEN_MANDATORY_LABEL tokenIL = (TOKEN_MANDATORY_LABEL)
Marshal.PtrToStructure(pTokenIL, typeof(TOKEN_MANDATORY_LABEL));
IntPtr pIL = NativeMethod.GetSidSubAuthority(tokenIL.Label.Sid, 0);
IL = Marshal.ReadInt32(pIL);
}
finally
{
if (hToken != null)
{
hToken.Close();
hToken = null;
}
if (pTokenIL != IntPtr.Zero)
{
Marshal.FreeHGlobal(pTokenIL);
pTokenIL = IntPtr.Zero;
cbTokenIL = 0;
}
}
return IL;
}
- How to show an UAC shield icon on the UI for tasks that require elevation?
bool fIsElevated = IsProcessElevated();
this.btnElevate.FlatStyle = FlatStyle.System;
NativeMethod.SendMessage(btnElevate.Handle, NativeMethod.BCM_SETSHIELD,
0, fIsElevated ? IntPtr.Zero : (IntPtr)1);
- How to self-elevate the current process?
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
try
{
Process.Start(proc);
}
catch
{
return;
}
Application.Exit();
- How to automatically elevate the process when it's started up?
If your application always requires administrative privileges, such as during an installation step, the operating system can automatically prompt the user for privileges elevation each time your application is invoked.
If a specific kind of resource (RT_MANIFEST
) is found embedded within the application executable, the system looks for the <trustInfo>
section and parses its contents. Here is an example of this section in the manifest file:
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
/>
</requestedPrivileges>
</security>
</trustInfo>
Three different values are possible for the level attribute:
requireAdministrator
The application must be started with Administrator privileges; it won't run otherwise.
highestAvailable
The application is started with the highest possible privileges. If the user is logged on with an Administrator account, an elevation prompt appears. If the user is a Standard User, the application is started (without any elevation prompt) with these standard privileges.
asInvoker
The application is started with the same privileges as the calling application.
To configure the elevation level in this Visual C# Windows Forms project, open the project's properties, turn to the Security tab, check the checkbox "Enable ClickOnce Security Settings", check "This is a fulltrust application" and close the application Properties page. This creates an app.manifest file and configures the project to embed the manifest. You can open the "app.manifest" file from Solution Explorer by expanding the Properties folder. The file has the following content by default.
="1.0" ="utf-8"
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
<applicationRequestMinimum>
<PermissionSet class="System.Security.PermissionSet" version="1"
Unrestricted="true" ID="Custom" SameSite="site" />
<defaultAssemblyRequest permissionSetReference="Custom" />
</applicationRequestMinimum>
</security>
</trustInfo>
</asmv1:assembly>
Here we are focusing on the line:
<requestedexecutionlevel uiaccess="false" level="asInvoker" />
You can change it to be:
<requestedexecutionlevel level="requireAdministrator" uiaccess="false" />
to require the application always be started with Administrator privileges.
Points of Interest
You may be particularly interested in how to perform the above UAC operations in native VC++ and VB.NET. You can find the answer in CppUACSelfElevation
and VBUACSelfElevation
sample packages.
Each sample package is accompanied with a ReadMe.txt file that documents the sample in detail.
If you have any feedback regarding the code samples or the entire All-In-One Code Framework project, please feel free to contact codefxf@microsoft.com.
History
- 16th March, 2010: Initial post
- 22nd March, 2010: Article updated