Detect if running as Administrator with or without elevated privileges?

54,052

Solution 1

Try this out:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class UacHelper
{
    private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
    private const string uacRegistryValue = "EnableLUA";

    private static uint STANDARD_RIGHTS_READ = 0x00020000;
    private static uint TOKEN_QUERY = 0x0008;
    private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

    public enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass
    }

    public enum TOKEN_ELEVATION_TYPE
    {
        TokenElevationTypeDefault = 1,
        TokenElevationTypeFull,
        TokenElevationTypeLimited
    }

    public static bool IsUacEnabled
    {
        get
        {
            RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false);
            bool result = uacKey.GetValue(uacRegistryValue).Equals(1);
            return result;
        }
    }

    public static bool IsProcessElevated
    {
        get
        {
            if (IsUacEnabled)
            {
                IntPtr tokenHandle;
                if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
                {
                    throw new ApplicationException("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());
                }

                TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;

                int elevationResultSize = Marshal.SizeOf((int)elevationResult);
                uint returnedSize = 0;
                IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);

                bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, elevationTypePtr, (uint)elevationResultSize, out returnedSize);
                if (success)
                {
                    elevationResult = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(elevationTypePtr);
                    bool isProcessAdmin = elevationResult == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
                    return isProcessAdmin;
                }
                else
                {
                    throw new ApplicationException("Unable to determine the current elevation.");
                }
            }
            else
            {
                WindowsIdentity identity = WindowsIdentity.GetCurrent();
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                bool result = principal.IsInRole(WindowsBuiltInRole.Administrator);
                return result;
            }
        }
    }
}

Solution 2

(new answer six years after the question was asked)

Disclaimer: This is just something that happened to work on my particular OS with my particular settings with my particular user:

using System.Security.Principal;

// ...

    static bool IsElevated
    {
      get
      {
        return WindowsIdentity.GetCurrent().Owner
          .IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
      }
    }

So when I run this "Run as administrator", the property get accessor returns true. When running normally (even if my user "is" administrator, just not running this particular application "as administrator"), it returns false.

This seems much simpler than many other answers.

I have no idea if there are cases where this fails.

PS! This also seems OK:

    static bool IsElevated
    {
      get
      {
        var id = WindowsIdentity.GetCurrent();
        return id.Owner != id.User;
      }
    }

Solution 3

Here is a modified version of this answer to include things like the proper disposing of resources and handling of Domain Administrators.

public static class UacHelper
{
    private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
    private const string uacRegistryValue = "EnableLUA";

    private static uint STANDARD_RIGHTS_READ = 0x00020000;
    private static uint TOKEN_QUERY = 0x0008;
    private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

    public enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass
    }

    public enum TOKEN_ELEVATION_TYPE
    {
        TokenElevationTypeDefault = 1,
        TokenElevationTypeFull,
        TokenElevationTypeLimited
    }

    public static bool IsUacEnabled
    {
        get
        {
            using (RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false))
            {
                bool result = uacKey.GetValue(uacRegistryValue).Equals(1);
                return result;
            }
        }
    }

    public static bool IsProcessElevated
    {
        get
        {
            if (IsUacEnabled)
            {
                IntPtr tokenHandle = IntPtr.Zero;
                if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
                {
                    throw new ApplicationException("Could not get process token.  Win32 Error Code: " +
                                                   Marshal.GetLastWin32Error());
                }

                try
                {
                    TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;

                    int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE));
                    uint returnedSize = 0;

                    IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);
                    try
                    {
                        bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType,
                                                           elevationTypePtr, (uint) elevationResultSize,
                                                           out returnedSize);
                        if (success)
                        {
                            elevationResult = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(elevationTypePtr);
                            bool isProcessAdmin = elevationResult == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
                            return isProcessAdmin;
                        }
                        else
                        {
                            throw new ApplicationException("Unable to determine the current elevation.");
                        }
                    }
                    finally
                    {
                        if (elevationTypePtr != IntPtr.Zero)
                            Marshal.FreeHGlobal(elevationTypePtr);
                    }
                }
                finally
                {
                    if (tokenHandle != IntPtr.Zero)
                        CloseHandle(tokenHandle);
                }
            }
            else
            {
                WindowsIdentity identity = WindowsIdentity.GetCurrent();
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                bool result = principal.IsInRole(WindowsBuiltInRole.Administrator) 
                           || principal.IsInRole(0x200); //Domain Administrator
                return result;
            }
        }
    }
}

Solution 4

The CodePlex project UAChelper has code that checks on elevation in UserAccountControl.cpp UserAccountControl::IsUserAdmin, that checks if UAC is enabled and then checks if process is elevated.

bool UserAccountControl::IsCurrentProcessElevated::get()
{
    return GetProcessTokenElevationType() == TokenElevationTypeFull;    //elevated
}

from the function:

int UserAccountControl::GetProcessTokenElevationType()
{
    HANDLE hToken;
    try
    {
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
            throw gcnew Win32Exception(GetLastError());

        TOKEN_ELEVATION_TYPE elevationType;
        DWORD dwSize;
        if (!GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize))
            throw gcnew Win32Exception(GetLastError());

        return elevationType;
    }
    finally
    {
        CloseHandle(hToken);
    }
}

Solution 5

In .net Framwork 4.5 I found another method that works for me. In relation to the following script that can be found here here (in German)

 rem --- Admintest.bat ---
 whoami /groups | find "S-1-5-32-544" > nul
 if errorlevel 1 goto ende
 echo Benutzer %username% ist lokaler Administrator.
 :ende

In C# it looks like this:

    private bool IsAdmin
    {
        get
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            if (identity != null)
            {
               WindowsPrincipal principal = new WindowsPrincipal(identity);
               List<Claim> list = new List<Claim>(principal.UserClaims);
               Claim c = list.Find(p => p.Value.Contains("S-1-5-32-544"));
               if (c != null)
                  return true;
            }
            return false;
        }
    }

But in .net < 4.5 the WindowsPrincipal class does not contain the UserClaims property and I found no way to get this information.

Share:
54,052

Related videos on Youtube

MiffTheFox
Author by

MiffTheFox

What am I even doing here?!

Updated on November 26, 2020

Comments

  • MiffTheFox
    MiffTheFox over 3 years

    I have an application that needs to detect whether or not it is running with elevated privileges or not. I currently have code set up like this:

    static bool IsAdministrator()
    {
        WindowsIdentity identity = WindowsIdentity.GetCurrent();
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        return principal.IsInRole (WindowsBuiltInRole.Administrator);
    }
    

    This works to detect if a user is an administrator or not, but doesn't work if running as an administrator without elevation. (For example in vshost.exe).

    How can I determine whether or not elevation is [already in force or] possible?

  • VSP
    VSP over 11 years
    Works if the account to run as is a local administrator but if you use the domain administrator the variable isProcessAdmin returns false. But UAC accepts the Domain Administrator as valid when elevating privileges (create folder in windows, run as administrator, etc)...How can i modify your function so it takes into account that case too?
  • Scott Chamberlain
    Scott Chamberlain over 10 years
    It all depends on which user you are running the service as. Are you trying to detect if the service is running as Local System, Local Service, Network Service, or a windows user? Detecting "administrative status" wont work for telling the difference between Local System and Local Service, you need to test for that by checking directly which user is running the process.
  • Mister Cook
    Mister Cook over 10 years
    You might also want to consider that if the account is the built in administrator then UAC is elevated by default so IsProcessElevated will return false in this case (because IsUacEnabled is true and elevationResult is TokenElevationTypeDefault) even though the process runs with in elevated mode without having prompted the user. Or in other words the account is elevated and the process runs in the default elevation type.
  • Scott Solmer
    Scott Solmer almost 10 years
    This code requires the following using statements: using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; It also seems to be mirrored here.
  • ferventcoder
    ferventcoder about 9 years
    I found CheckTokenMembership insufficient when subject to UAC - github.com/chocolatey/choco/blob/… returns false. Check the code (I'm replacing it) and take a look at the output from Win2012R2 - i.imgur.com/gX3JP0W.png
  • Anders
    Anders about 9 years
    @ferventcoder It depends on what you really want to know; is the user a elevated administrator right now or can they elevate if required. You can for example check TOKEN_ELEVATION_TYPE and end up with something like: bool is_or_can_elevate() { return process_is_elevated() || TokenElevationTypeLimited == get_current_token_elevation_type(); }. Another issue is that the definition of elevated is not the same everywhere, you can have a console window with the "Administrator: " prefix and at the same time be below High integrity level! TokenElevation does not always match TokenIntegrityLevel.
  • ferventcoder
    ferventcoder about 9 years
    Fun times. I want to know if I have an elevated process separate from whether the user is an administrator. Here's where I ended up. Let me know where I should go if it is wrong - github.com/chocolatey/choco/issues/77#issuecomment-73523774 and github.com/chocolatey/choco/commit/…
  • Anders
    Anders about 9 years
    @ferventcoder is_processes_elevated() { return CheckTokenMembership/IsInRole || TokenElevation/TokenIntegrityLevel>=0x3000; } CheckTokenMembership or IsInRole for < Vista and Vista+ with UAC off. TokenElevation or TokenIntegrityLevel>=0x3000 depending on exactly how you want to detect the elevation. I believe conhost.exe uses TokenElevation but it is broken IMHO and you should check the actual level... (You need special tools to generate a token that fools TokenElevation though) See also: windowssucks.wordpress.com/2011/02/07/uac-are-you-high/#
  • Anders
    Anders about 9 years
    ...and even that is sort of wrong, in theory it is possible to have a elevated token and not be in the administrators group. So if you only want people in the administrators group and make sure that they are elevated you should perform the CheckTokenMembership/IsInRole check and then the Token* check should fail (No UAC) or it's value should indicate elevation... This of course depends on what the you actually want to access. You might need to be system/admin and elevated, or just elevated, it depends on the ACL.
  • ferventcoder
    ferventcoder about 9 years
    Yep, if you read my comments in there you can see I mention that. We only use the detection for informational purposes now.
  • ferventcoder
    ferventcoder about 9 years
    Reading over that code, we check a user first based on a quick win (IsInRole), then switch over to the token elevation. In most cases we are going to catch administrators who are not elevated but in some minor cases we may catch others as well. We'll generate a warning when is_admin and is_process_elevated don't match.
  • MickyD
    MickyD about 9 years
    This is not an answer but arguably commentary on another post
  • Lewis
    Lewis over 8 years
    Thanks for this! - I used this in PowerShell [Security.Principal.WindowsIdentity]::GetCurrent().Owner.IsW‌​ellKnown([System.Sec‌​urity.Principal.Well‌​KnownSidType]::Built‌​inAdministratorsSid)
  • CularBytes
    CularBytes about 8 years
    When having set notifications to 'never show any notification', this will return true. Perhaps in certain scenario's where you really need to run the software as administrator it can give a false indication.
  • CularBytes
    CularBytes almost 8 years
    This got me an exception at Windows 8, at Marshal.SizeOf((int)elevationResult) I am not sure why yet. Exception message is: Method not found. At: Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
  • CularBytes
    CularBytes almost 8 years
    This got me an exception at Windows 8, at Marshal.SizeOf((int)elevationResult) I am not sure why yet. Exception message is: Method not found. At: Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
  • Scott Chamberlain
    Scott Chamberlain almost 8 years
    @RageCompex are you using a restricted platform like a universal app or Unity3d?
  • CularBytes
    CularBytes almost 8 years
    Well it is a customer that I receive the error from, automatic logging, All I know is that it doesn't work on his/her pc. All I know until now is that it is a Windows 8, 64x bit, 2 processors. I suspect it is due old .NET version, Marshal.SizeOf is supported since 4.5.1 I can read elsewhere..
  • CularBytes
    CularBytes almost 8 years
    FYI: Only determining if account is administrator, not if the app is elevated
  • Scott Chamberlain
    Scott Chamberlain almost 8 years
    @RageCompex its been available sense .NET 1.1. Perhaps you have a typo?
  • CularBytes
    CularBytes almost 8 years
    Yea, thats what I thought :( No it is working correctly on mine and about 100 others... full stack trace: pastebin.com/ebSWARfu
  • Scott Chamberlain
    Scott Chamberlain almost 8 years
    Ah, you are compiling with 4.5.1 because of that it is trying to use this overload but the user does not have 4.5.1 installed. Try replacing it with Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE)),
  • CularBytes
    CularBytes almost 8 years
    Thanks @ScottChamberlain The user updated to 4.5.2 (which I target) and it solved the problem. This solution is probably good for backwards compatibility.
  • Martin Braun
    Martin Braun over 7 years
    @ScottChamberlain int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE)) throws an ArgumentException on 32 Bit application .NET 4.0, int elevationResultSize = Marshal.SizeOf((int)elevationResult) worked, however.
  • Roman Starkov
    Roman Starkov over 7 years
    This will not distinguish between "semi-unelevated" process and a properly-unelevated process: it's possible that IsElevated will return false but the process may still be running with High integrity level. A genuinely non-elevated process has a medium integrity level. This is probably irrelevant for 99% of the applications, but it's worth mentioning because tools like Process Hacker might still declare such a process to be elevated. A "semi-unelevated" process is not something you'd see normally; it might occur when someone fails to launch an unelevated child process correctly.
  • Olivier MATROT
    Olivier MATROT over 7 years
    What about TokenElevationTypeLimited ? Should it not be considered to set isProcessAdmin to true ?
  • StingyJack
    StingyJack over 6 years
    Whats "running with High integrity level"?
  • Roman Starkov
    Roman Starkov over 6 years
    @StingyJack that's too big of a question to answer in comments, but see here and here.
  • StingyJack
    StingyJack over 6 years
    Thanks @RomanStarkov and Jeppe, 20+ years in the business and I hadn't heard the term before.
  • Adam
    Adam over 6 years
    To do check if a user is a member of S-1-5-32-544 (Administrators group) in .Net < 4.5, you can just use the code in the original question. The principal will only be a member of the Administrators group if the process is running elevated and the user is in the group. If the process is not elevated the principal will not be in the group.
  • Matt
    Matt about 6 years
    Nice answer, short and efficient, I gave you a +1 for it. N.B. I made this a property in my code (private bool IsAdmin{ get { ... } }), then you don't need the brackets if you invoke IsAdmin.
  • Santhosh
    Santhosh over 5 years
    This code works pretty well with Visual Studio Setup project custom actions.I am trying to move to InstallShield installer basic msi project and calling the same above code gives me different values. elevationResult value is different with VS vs. IS installers when running on same machine with same user. VS Installer: elevationResult value is TokenElevationTypeDefault and IsAdministrator is true. IS Installer: elevationResult value is TokenElevationTypeFull and IsAdministrator is false. Anyone observed same issue? Any ideas why different behavior?
  • T.Todua
    T.Todua about 4 years
    How to check for other process (by name) , i.e. if other_process.exe running in admin or not?
  • 0xC0000022L
    0xC0000022L about 3 years
    Technically this relies on an implementation detail. The fact, that the "owner" field of the token points to the built-in Administrators group. However, no one's to say this implementation detail is there to stay and the appropriate method is to check whether the current security context is elevated or not!
  • Benj
    Benj about 3 years
    This isn't really right, the owner of a security token generally will be admin if it's an elevated token but it doesn't actually have to be. Also you can have a non-elevated security token owned by admin. The true test of whether a token is elevated is whether it has the admin SID in list of granted access SIDs in the ACLs because that's what will actually make it pass the ACL test.
  • A. Niese
    A. Niese over 2 years
    This answer does not detect elevation on Windows Server 2019 on an administrator account. However, this answer does: stackoverflow.com/a/55079599/6079533