86
votes

My application needs to run some scripts, and I must be sure that the user running them is an administrator... What is the best way of doing this using C#?

8

8 Answers

98
votes
using System.Security.Principal;

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

You can also call into the Windows API to do this:

[DllImport("shell32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsUserAnAdmin();

which more generically tells you whether user is running under elevated rights.

14
votes

The above answers with IsInRole are actually correct: it does check if the current user has admin privilege. However,

Starting with Windows Vista, User Account Control (UAC) determines the privileges of a user. If you are a member of the Built-in Administrators group, you are assigned two run-time access tokens: a standard user access token and an administrator access token. By default, you are in the standard user role.

(from MSDN, e.g. https://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogpermission(v=vs.110).aspx)

Thus, IsInRole will per default consider the user privilege, and thus the method return false. Only true when the software is explicitly run as administrator.

The other method checking AD in https://ayende.com/blog/158401/are-you-an-administrator will check if the user name is in an admin group.

My complete method combining both is thus:

    public static bool IsCurrentUserAdmin(bool checkCurrentRole = true)
    {
        bool isElevated = false;

        using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
        {
            if (checkCurrentRole)
            {
                // Even if the user is defined in the Admin group, UAC defines 2 roles: one user and one admin. 
                // IsInRole consider the current default role as user, thus will return false!
                // Will consider the admin role only if the app is explicitly run as admin!
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                isElevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
            else
            {
                // read all roles for the current identity name, asking ActiveDirectory
                isElevated = IsAdministratorNoCache(identity.Name);
            }
        }

        return isElevated;
    }

    /// <summary>
    /// Determines whether the specified user is an administrator.
    /// </summary>
    /// <param name="username">The user name.</param>
    /// <returns>
    ///   <c>true</c> if the specified user is an administrator; otherwise, <c>false</c>.
    /// </returns>
    /// <seealso href="https://ayende.com/blog/158401/are-you-an-administrator"/>
    private static bool IsAdministratorNoCache(string username)
    {
        PrincipalContext ctx;
        try
        {
            Domain.GetComputerDomain();
            try
            {
                ctx = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                // can't access domain, check local machine instead 
                ctx = new PrincipalContext(ContextType.Machine);
            }
        }
        catch (ActiveDirectoryObjectNotFoundException)
        {
            // not in a domain
            ctx = new PrincipalContext(ContextType.Machine);
        }
        var up = UserPrincipal.FindByIdentity(ctx, username);
        if (up != null)
        {
            PrincipalSearchResult<Principal> authGroups = up.GetAuthorizationGroups();
            return authGroups.Any(principal =>
                                  principal.Sid.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountDomainAdminsSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountAdministratorSid) ||
                                  principal.Sid.IsWellKnown(WellKnownSidType.AccountEnterpriseAdminsSid));
        }
        return false;
    }

For a user in an admin group without elevated privilege (UAC enabled), this method IsCurrentUserAdmin() return !checkCurrentRole: true if checkCurrentRole==false, but false if checkCurrentRole==true

If you run code that REQUIRES admin privilege, consider the checkCurrentRole==true. Otherwise, you'll get a security exception by then. Therefore the correct IsInRole logic.

2
votes

Just thought I'd add another solution; as the IsInRole doesn't always work.

  • If the user isn't a member of the specified Windows User Group in the current session.
  • The administrator has made changes in the Group Policy Settings
  • The role parameter is treated as a 'Case Sensitive' method.
  • And if an XP machine doesn't have the .NET Framework Version installed it won't work.

Depending on your needs if you need to support older systems; or are unsure of how your client is physically managing your system. This is a solution I implemented; for flexibility and alterations.

class Elevated_Rights
    {

        // Token Bool:
        private bool _level = false;

        #region Constructor:

        protected Elevated_Rights()
        {

            // Invoke Method On Creation:
            Elevate();

        }

        #endregion

        public void Elevate()
        {

            // Get Identity:
            WindowsIdentity user = WindowsIdentity.GetCurrent();

            // Set Principal
            WindowsPrincipal role = new WindowsPrincipal(user);

            #region Test Operating System for UAC:

            if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
            {

                // False:
                _level = false;

                // Todo: Exception/ Exception Log

            }

            #endregion

            else
            {

                #region Test Identity Not Null:

                if (user == null)
                {

                    // False:
                    _level = false;

                    // Todo: "Exception Log / Exception"

                }

                #endregion

                else
                {

                    #region Ensure Security Role:

                    if (!(role.IsInRole(WindowsBuiltInRole.Administrator)))
                    {

                        // False:
                        _level = false;

                        // Todo: "Exception Log / Exception"

                    }

                    else
                    {

                        // True:
                        _level = true;

                    }

                    #endregion


                } // Nested Else 'Close'

            } // Initial Else 'Close'

        } // End of Class.

So the above code has a few constructs; it will actually test to see if the User is on Vista or higher. That way if a customer is on XP without a framework or beta framework from years ago it will allow you to alter what you'd like to do.

Then it will physically test to avoid a null value for the account.

Then last of all it will provide the check to verify that the user is indeed in the proper role.

I know the question has been answered; but I thought my solution would be a great addition to the page for anyone else whom is searching Stack. My reasoning behind the Protected Constructor would allow you to use this class as a Derived Class that you could control the state of when the class is instantiated.

0
votes

I must be sure that the user running them is an administrator

If your application must be run with admin rights, it would be right to update its manifest.
Set requestedExecutionlevel to requireAdminstrator.

0
votes

This is how I end up... I'm forcing my app to run as administrator mode. To do this

1- Add <ApplicationManifest>app.manifest</ApplicationManifest> to your csproj file.

MyProject.csproj

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <ApplicationManifest>app.manifest</ApplicationManifest>
  </PropertyGroup>    
</Project>

2- Add the below app.manifest file to your project.

app.manifest

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <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="requireAdministrator" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>
0
votes

Like others here, my program is not running elevated, so this code returns false is UAC is enabled:

private bool IsCurrentUserAnAdmin()
{
    var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}

@EricBDev's answer with IsAdministratorNoCache does return true if my program is not running elevated, and the user is an Admin. However, like the blog author says, it is very slow.

Here is my solution; it emulates IsAdministratorNoCache but is fast:

private bool IsCurrentUserInAdminGroup()
{
    // https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/security-identifiers-in-windows
    // S-1-5-32-544
    // A built-in group. After the initial installation of the operating system,
    // the only member of the group is the Administrator account.
    // When a computer joins a domain, the Domain Admins group is added to
    // the Administrators group. When a server becomes a domain controller,
    // the Enterprise Admins group also is added to the Administrators group.
    var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    var claims = principal.Claims;
    return (claims.FirstOrDefault(c => c.Value == "S-1-5-32-544") != null);
}