51 votes

En .NET/C#, testez si le processus a des privilèges administratifs.

Existe-t-il un moyen canonique de tester si le processus a des privilèges administratifs sur une machine ?

Je vais lancer un processus de longue durée, et bien plus tard dans la vie du processus, il va tenter certaines choses qui nécessitent des privilèges d'administrateur.

J'aimerais pouvoir tester dès le départ si le processus a ces droits plutôt que plus tard.

79voto

Wadih M. Points 5161

Cela permettra de vérifier si l'utilisateur fait partie du groupe des administrateurs locaux (en supposant que vous ne vérifiez pas les droits d'administrateur de domaine).

using System.Security.Principal;

public bool IsUserAdministrator()
{
    //bool value to hold our return value
    bool isAdmin;
    WindowsIdentity user = null;
    try
    {
        //get the currently logged in user
        user = WindowsIdentity.GetCurrent();
        WindowsPrincipal principal = new WindowsPrincipal(user);
        isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
    }
    catch (UnauthorizedAccessException ex)
    {
        isAdmin = false;
    }
    catch (Exception ex)
    {
        isAdmin = false;
    }
    finally
    {
        if (user != null)
            user.Dispose();
    }
    return isAdmin;
}

3 votes

Cela déterminera si l'utilisateur se trouve dans la section BUILTIN \Administrators mais est-ce que cela apparaîtra si l'utilisateur est en position élevée sous Vista ?

1 votes

Est-il vraiment nécessaire d'attraper chaque exception ?

0 votes

Si quelqu'un peut tester cela sur Vista, ce serait formidable.

30voto

David Moore Points 481

En commençant par le code de Wadih M, j'ai ajouté du code P/Invoke pour essayer de gérer le cas où l'UAC est activé.

http://www.davidmoore.info/blog/2011/06/20/how-to-check-if-the-current-user-is-an-administrator-even-if-uac-is-on/

Tout d'abord, nous avons besoin de code pour prendre en charge l'appel de l'API GetTokenInformation :

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(IntPtr tokenHandle, TokenInformationClass tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength);

/// <summary>
/// Passed to <see cref="GetTokenInformation"/> to specify what
/// information about the token to return.
/// </summary>
enum TokenInformationClass
{
     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
}

/// <summary>
/// The elevation type for a user token.
/// </summary>
enum TokenElevationType
{
    TokenElevationTypeDefault = 1,
    TokenElevationTypeFull,
    TokenElevationTypeLimited
}

Ensuite, le code réel pour détecter si l'utilisateur est un administrateur (en retournant true si c'est le cas, false sinon).

var identity = WindowsIdentity.GetCurrent();
if (identity == null) throw new InvalidOperationException("Couldn't get the current user identity");
var principal = new WindowsPrincipal(identity);

// Check if this user has the Administrator role. If they do, return immediately.
// If UAC is on, and the process is not elevated, then this will actually return false.
if (principal.IsInRole(WindowsBuiltInRole.Administrator)) return true;

// If we're not running in Vista onwards, we don't have to worry about checking for UAC.
if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
{
     // Operating system does not support UAC; skipping elevation check.
     return false;
}

int tokenInfLength = Marshal.SizeOf(typeof(int));
IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength);

try
{
    var token = identity.Token;
    var result = GetTokenInformation(token, TokenInformationClass.TokenElevationType, tokenInformation, tokenInfLength, out tokenInfLength);

    if (!result)
    {
        var exception = Marshal.GetExceptionForHR( Marshal.GetHRForLastWin32Error() );
        throw new InvalidOperationException("Couldn't get token information", exception);
    }

    var elevationType = (TokenElevationType)Marshal.ReadInt32(tokenInformation);

    switch (elevationType)
    {
        case TokenElevationType.TokenElevationTypeDefault:
            // TokenElevationTypeDefault - User is not using a split token, so they cannot elevate.
            return false;
        case TokenElevationType.TokenElevationTypeFull:
            // TokenElevationTypeFull - User has a split token, and the process is running elevated. Assuming they're an administrator.
            return true;
        case TokenElevationType.TokenElevationTypeLimited:
            // TokenElevationTypeLimited - User has a split token, but the process is not running elevated. Assuming they're an administrator.
            return true;
        default:
            // Unknown token elevation type.
            return false;
     }
}
finally
{    
    if (tokenInformation != IntPtr.Zero) Marshal.FreeHGlobal(tokenInformation);
}

1 votes

Il s'agit de la réponse la plus complète, qui résout les problèmes où l'appel à IsInRole(WindowsBuiltInRole.Administrator) renvoie false parce que l'UAC bloque. Il a été confirmé que cette solution fonctionne correctement sous Windows 8.

0 votes

C'est une excellente réponse, mais pas à cette question !

17voto

Jacob Proffitt Points 8187

Si vous voulez vous assurer que votre solution fonctionne sous Vista UAC et que vous disposez de .Net Framework 3.5 ou mieux, vous pouvez utiliser l'espace de noms System.DirectoryServices.AccountManagement. Votre code ressemblerait à quelque chose comme :

bool isAllowed = false;
using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, null))
{
    UserPrincipal up = UserPrincipal.Current;
    GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "Administrators");
    if (up.IsMemberOf(gp))
        isAllowed = true;
}

0 votes

Il devrait . Je ne l'ai pas testé contre le compte builtin.Administrators. Mon application était testée contre un domaine. theruntime.com/blogs/jacob/archive/2009/02/13/

7 votes

S'IL VOUS PLAÎT, ne codifiez pas en dur les administrateurs (je suis sûr qu'il s'agit de la chaîne localisable, et non de la chaîne BUILTIN \ADministrators chaîne bien connue)

0 votes

Alors qu'est-ce que tu utiliserais, Ruben ?

3voto

Jens Points 14829

Avec le .NET Framework 4.5, il semble plus facile de vérifier si un utilisateur fait partie du groupe des administrateurs :

WindowsPrincipal principal = WindowsPrincipal.Current;
bool canBeAdmin = principal.Claims.Any((c) => c.Value == "S-1-5-32-544");

0 votes

Attention - il y a une grande différence entre la liste des réclamations qui est retournée entre WindowsPrincipal.Current.Claims et (new WindowsPrincipal(WindowsIdentity.GetCurrent())).Claims voir ma réponse ci-dessous

3voto

Alex G. Points 39

J'ai essayé le code d'Erwin mais il ne compile pas.

Je l'ai fait fonctionner comme ça :

[DllImport("shell32.dll")] public static extern bool IsUserAnAdmin();

0 votes

Cela a fonctionné comme un champion pour moi - quelqu'un a une idée de ce à quoi ressemble le code à l'intérieur de la fonction IsUserAnAdmin ?

6 votes

-1 : La page MSDN pour IsUserAnAdmin lien déclare : "Fin du support client : Windows Vista". Cette fonction pourrait ne plus être disponible pour les futures versions de Windows, et ce n'est donc pas la méthode "canonique".

0 votes

On dirait que la partie "Fin du support client : Windows Vista" a été supprimé de l'article, bien qu'il fasse toujours allusion à une éventuelle [dépréciation].

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X