Wykryć, czy działasz jako administrator z podwyższonymi uprawnieniami czy bez?


82

Mam aplikację, która musi wykryć, czy działa z podwyższonymi uprawnieniami, czy nie. Obecnie mam ustawiony kod w następujący sposób:

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

Działa to w celu wykrycia, czy użytkownik jest administratorem, czy nie, ale nie działa, jeśli działa jako administrator bez uprawnień. (Na przykład w vshost.exe).

Jak mogę ustalić, czy podwyższenie jest [już obowiązujące lub] możliwe ?

Odpowiedzi:


55

Wypróbuj to:

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;
            }
        }
    }
}

8
Działa, jeśli konto ma działać jako administrator lokalny, ale jeśli używasz administratora domeny, zmienna isProcessAdmin zwraca wartość false. Ale UAC akceptuje administratora domeny jako poprawnego podczas podnoszenia uprawnień (tworzenie folderu w systemie Windows, uruchamianie jako administrator itp.) ... Jak mogę zmodyfikować twoją funkcję, aby uwzględniała również ten przypadek?
VSP,

1
Możesz również wziąć pod uwagę, że jeśli konto jest wbudowanym administratorem, to UAC jest domyślnie podwyższone, więc IsProcessElevated zwróci w tym przypadku false (ponieważ IsUacEnabled ma wartość true, a elevationResult to TokenElevationTypeDefault), mimo że proces działa w trybie podwyższonym bez konieczności - zachęcił użytkownika. Innymi słowy, konto jest podwyższone, a proces działa z domyślnym typem podniesienia uprawnień.
Mister Cook

2
Ten kod wymaga następujących instrukcji using: using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; Wydaje się, że jest to odzwierciedlone tutaj.
Scott Solmer

To dał mi wyjątek w systemie Windows 8, w którym Marshal.SizeOf((int)elevationResult)nie jestem jeszcze pewien, dlaczego. Komunikat o wyjątku: Nie znaleziono metody. O:Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
CularBytes,

A co z TokenElevationTypeLimited? Czy nie należy uważać, że ustawienie isProcessAdmin na wartość true?
Olivier MATROT

34

(nowa odpowiedź sześć lat po zadaniu pytania)

Zastrzeżenie: to tylko coś, co działało w moim konkretnym systemie operacyjnym z moimi określonymi ustawieniami dla mojego konkretnego użytkownika:

using System.Security.Principal;

// ...

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

Więc kiedy uruchamiam to „Uruchom jako administrator”, metoda getdostępu właściwości zwraca true. Podczas normalnego działania (nawet jeśli mój użytkownik „jest” administratorem, po prostu nie uruchamia tej konkretnej aplikacji „jako administrator”), zwraca false.

Wydaje się to o wiele prostsze niż wiele innych odpowiedzi.

Nie mam pojęcia, czy są przypadki, w których to się nie powiedzie.

PS! To również wydaje się OK:

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

1
Dzięki za to! - Użyłem tego w PowerShell [Security.Principal.WindowsIdentity] :: GetCurrent (). Owner.IsWellKnown ([System.Security.Principal.WellKnownSidType] :: BuiltinAdministratorsSid)
Lewis

Po ustawieniu powiadomień na „nigdy nie pokazuj żadnych powiadomień”, zwróci to wartość „prawda”. Być może w pewnych sytuacjach, w których naprawdę musisz uruchomić oprogramowanie jako administrator, może to dać fałszywe wskazanie.
CularBytes

2
Nie spowoduje to rozróżnienia między procesem „częściowo nienaruszonym” a procesem prawidłowo niewniesionym: możliwe, że IsElevatedzwróci błąd, ale proces może nadal działać z wysokim poziomem integralności. Prawdziwie niewysoki proces ma średni poziom integralności. Prawdopodobnie nie ma to znaczenia w przypadku 99% aplikacji, ale warto o tym wspomnieć, ponieważ narzędzia takie jak Process Hacker mogą nadal deklarować podniesienie poziomu takiego procesu. Proces „częściowo niewniesiony” nie jest czymś, co można zobaczyć normalnie; może się to zdarzyć, gdy ktoś nie uruchomi poprawnie niewniesionego procesu potomnego.
Roman Starkov

Co „działa z wysokim poziomem integralności”?
StingyJack

@StingyJack to zbyt duże pytanie, aby odpowiadać w komentarzach, ale spójrz tutaj i tutaj .
Roman Starkov

19

Oto zmodyfikowana wersja tej odpowiedzi, która obejmuje takie rzeczy, jak właściwe usuwanie zasobów i obsługa administratorów domeny.

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;
            }
        }
    }
}

Wszystko zależy od tego, jako użytkownik uruchamiasz usługę. Czy próbujesz wykryć, czy usługa działa jako system lokalny, usługa lokalna, usługa sieciowa czy użytkownik systemu Windows? Wykrywanie „statusu administracyjnego” nie zadziała w celu określenia różnicy między systemem lokalnym a usługą lokalną. Musisz to sprawdzić, sprawdzając bezpośrednio, który użytkownik uruchamia proces.
Scott Chamberlain

To dał mi wyjątek w systemie Windows 8, w którym Marshal.SizeOf((int)elevationResult)nie jestem jeszcze pewien, dlaczego. Komunikat o wyjątku: Nie znaleziono metody. O:Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
CularBytes,

@RageCompex Czy korzystasz z platformy z ograniczeniami, takiej jak aplikacja uniwersalna lub Unity3d?
Scott Chamberlain

1
Ach, kompilujesz z 4.5.1, ponieważ próbuje użyć tego przeciążenia, ale użytkownik nie ma zainstalowanego 4.5.1. Spróbuj go zastąpić Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE)),
Scott Chamberlain

2
@ScottChamberlain int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE))rzuca ArgumentException32-bitową aplikację .NET 4.0 int elevationResultSize = Marshal.SizeOf((int)elevationResult), jednak zadziałała.
Martin Braun,

16

Projekt CodePlex UAChelper ma kod, który sprawdza podniesienie uprawnień w UserAccountControl.cppUserAccountControl::IsUserAdmin , który sprawdza, czy UAC jest włączony, a następnie sprawdza, czy proces jest podniesiony.

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

z funkcji:

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);
    }
}

10

W .net Framwork 4.5 znalazłem inną metodę, która działa dla mnie. W związku z następującym skryptem, który można znaleźć tutaj (w języku niemieckim)

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

W C # wygląda to tak:

    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;
        }
    }

Ale w .net <4.5 WindowsPrincipalklasa nie zawiera UserClaimswłaściwości i nie znalazłem sposobu na uzyskanie tych informacji.


Do Twojej wiadomości: tylko określanie, czy konto jest administratorem, a nie, czy aplikacja jest podniesiona
CularBytes,

Aby sprawdzić, czy użytkownik jest członkiem S-1-5-32-544 (grupy Administratorzy) w .Net <4.5, możesz po prostu użyć kodu z pierwotnego pytania. Jednostka główna będzie członkiem grupy Administratorzy tylko wtedy, gdy proces działa z podwyższonym poziomem uprawnień, a użytkownik znajduje się w grupie. Jeśli proces nie zostanie podniesiony, podmiot główny nie będzie w grupie.
Adam

1
Ładna odpowiedź, krótka i skuteczna, dałem ci za nią +1. Uwaga: utworzyłem tę właściwość w moim kodzie ( private bool IsAdmin{ get { ... } }), więc nie potrzebujesz nawiasów, jeśli wywołasz IsAdmin.
Matt

4

Używanie TokenElevationTypemogłoby zadziałać, ale jeśli użyjesz PInvoke CheckTokenMembership()przeciwko identyfikatorowi SID grupy administratorów, twój kod będzie działał również, gdy UAC jest wyłączony i na 2000 / XP / 2003, a także będzie obsługiwał odmowy identyfikatorów SID.

Istnieje również IsUserAnAdmin()funkcja, która CheckTokenMembershipsprawdza za Ciebie, ale MSDN twierdzi, że może nie istnieć na zawsze


Zauważyłem, że CheckTokenMembership jest niewystarczające, gdy podlega UAC - github.com/chocolatey/choco/blob/ ... zwraca fałsz. Sprawdź kod (zastępuję go) i spójrz na wyjście z Win2012R2 - i.imgur.com/gX3JP0W.png
ferventcoder

@ferventcoder To zależy od tego, co naprawdę chcesz wiedzieć; czy użytkownik jest teraz administratorem z wyższym poziomem uprawnień, czy może w razie potrzeby może to zrobić. Możesz na przykład sprawdzić TOKEN_ELEVATION_TYPE i otrzymać coś takiego: bool is_or_can_elevate () {return process_is_elevated () || TokenElevationTypeLimited == get_current_token_elevation_type (); }. Inną kwestią jest to, że definicja podwyższonego poziomu nie jest wszędzie taka sama, możesz mieć okno konsoli z prefiksem „Administrator:” i jednocześnie znajdować się poniżej poziomu wysokiego! TokenElevation nie zawsze pasuje do TokenIntegrityLevel.
Anders

Dobre czasy. Chcę wiedzieć, czy mam podwyższony proces niezależnie od tego, czy użytkownik jest administratorem. Oto gdzie skończyłem. Daj mi znać, gdzie mam iść, jeśli jest źle - github.com/chocolatey/choco/issues/77#issuecomment-73523774 i github.com/chocolatey/choco/commit/…
ferventcoder

@ferventcoder is_processes_elevated () {return CheckTokenMembership / IsInRole || TokenElevation / TokenIntegrityLevel> = 0x3000; } CheckTokenMembership lub IsInRole dla <Vista i Vista + z wyłączoną kontrolą konta użytkownika. TokenElevation lub TokenIntegrityLevel> = 0x3000 w zależności od tego, jak dokładnie chcesz wykryć podniesienie. Uważam, że conhost.exe używa TokenElevation, ale jest uszkodzony IMHO i powinieneś sprawdzić rzeczywisty poziom ... (Potrzebujesz specjalnych narzędzi do wygenerowania tokena, który oszukuje TokenElevation) Zobacz też: windowssucks.wordpress.com/2011/02/07 / uac-are-you-high / #
Anders

... i nawet to jest trochę błędne, w teorii można mieć podwyższony token i nie być w grupie administratorów. Więc jeśli chcesz tylko ludzi w grupie administratorów i upewnij się, że mają podwyższone uprawnienia, powinieneś wykonać sprawdzenie CheckTokenMembership / IsInRole, a następnie sprawdzenie Token * powinno zakończyć się niepowodzeniem (bez UAC) lub jego wartość powinna wskazywać podniesienie uprawnień ... To oczywiście zależy do czego faktycznie chcesz uzyskać dostęp. Może być konieczne posiadanie statusu systemu / administratora i podwyższonego poziomu lub tylko podwyższenie uprawnień, zależy to od listy ACL.
Anders

4

Ta odpowiedź ma kilka problemów. Po pierwsze, nie pobiera żadnych procesów systemowych działających jako administrator (na przykład w ramach NT-Authority / SYSTEM). Poniższy przykład kodu rozwiązuje wszystkie problemy (wykrywa, LocalAdmins, DomainAdmins i LocalSystemAdmins)

Jeśli chcesz po prostu bieżącego procesu, wymienić pHandlezProcess.GetCurrentProcess().Handle

UWAGA: Aby go uruchomić, musisz mieć określone uprawnienia. (Każdy proces administracyjny ma je, ale najpierw musi je aktywować, usługi mają je domyślnie aktywowane)

internal static bool IsProcessElevatedEx(this IntPtr pHandle) {

        var token = IntPtr.Zero;
        if (!OpenProcessToken(pHandle, MAXIMUM_ALLOWED, ref token))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");

        WindowsIdentity identity = new WindowsIdentity(token);
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        bool result = principal.IsInRole(WindowsBuiltInRole.Administrator)
                   || principal.IsInRole(0x200); //Domain Administrator
        CloseHandle(token);
        return result;
}

1

Myślę, że jest jeszcze jeden problem. Sprawdziłem dostarczone przez Ciebie rozwiązania i muszę powiedzieć, że przy instalacji Windows 7 i zalogowałem się jako administrator sprawdzanie nie działa. System Windows nigdy nie zwraca informacji, że proces działa w trybie podwyższonym. A więc sekwencja:

if (IsUacEnabled)
    return IsProcessInElevatedMode();
return IsUserAdmin();

nie zwraca prawdy, gdy jest zalogowany jako Administrator, ale proces ma wszystkie uprawnienia do wykonywania operacji systemowych (np. zatrzymywania usług systemowych). Sekwencja robocza to:

if (IsUserAdmin())
    return true;

if (IsUacEnabled)
    return IsProcessInElevatedMode();

return false;

Najpierw sprawdź, czy proces jest uruchamiany w kontekście administratora. Dodatkowe informacje:

IsUacEnabled() - checks if the UAC has been enabled in the system (Windows)
IsProcessInElevatedMode() - checks if the process is run in an elevated mode
IsUserAdmin() - checks if the current user has an Administrtor role

Wszystkie te metody zostały opisane w poprzednich postach.


1
To nie jest odpowiedź, ale zapewne komentarz do innego postu
MickyD

1

Korzystanie z pakietu NuGet UACHelper : https://www.nuget.org/packages/UACHelper/

if (UACHelper.IsElevated)
    // something
else
    // something else

Istnieje wiele innych właściwości, których można użyć do wykrycia, czy użytkownik jest w rzeczywistości administratorem, czy proces działa w ramach wirtualizacji UAC, lub czy właściciel pulpitu jest właścicielem procesu. (Uruchom jak z ograniczonego konta)

Sprawdź przeczytaj mnie, aby uzyskać więcej informacji.


1

Używam tego kodu i działa dobrze:


bool runningAsAdmin = WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);

* Admin jest częścią grupy Build-In Administrators.

„Konto użytkownika dla administratora systemu. To konto jest pierwszym kontem utworzonym podczas instalacji systemu operacyjnego. Konto nie może zostać usunięte ani zablokowane. Jest członkiem grupy Administratorzy i nie można go usunąć z tej grupy”. - https://ss64.com/nt/syntax-security_groups.html

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.