← Opsidian
Poradnik

Jak znaleźć nieaktywne konta Guest w Entra ID

Konta gościnne to rzecz, która najłatwiej w tenancie narasta i najtrudniej się ją sprząta. Ktoś zaprasza agencję do jednej kampanii, konsultanta do jednej migracji, audytora na tydzień w marcu. Projekt się kończy, zaproszenie nie. Dwa lata później w katalogu siedzi kilkaset zewnętrznych tożsamości i nikt nie potrafi powiedzieć, które z nich nadal potrzebują dostępu.

Część mechaniczna — wylistowanie gości i ich ostatnich logowań — zajmuje jakieś pięć minut. Problemy zaczynają się przy ocenie, więc zanim cokolwiek wyłączysz, warto zrozumieć, co te dane właściwie mówią.

Co Entra ID naprawdę Ci pokazuje

Każdy obiekt użytkownika w Microsoft Graph ma właściwość signInActivity, a w niej między innymi lastSignInDateTime i lastNonInteractiveSignInDateTime. Do jej odczytania potrzebne jest uprawnienie AuditLog.Read.All obok User.Read.All — szczegół, który wykłada większość pierwszych podejść, bo bez niego właściwość po prostu wraca pusta, zamiast rzucić czytelnym błędem.

Dwa zastrzeżenia ważą więcej niż sama składnia:

  • Dane o logowaniach zależą od licencji. Pełne raportowanie logowań to funkcja płatna — na tenancie bez Entra ID P1 lub P2 możesz nie dostać nic. Puste signInActivity nie jest więc dowodem na to, że konto jest nieaktywne. Jest dowodem na brak danych.
  • Logowanie interaktywne to nie cała historia. Konto może wyglądać na uśpione w lastSignInDateTime, podczas gdy lastNonInteractiveSignInDateTime pokazuje regularne odświeżanie tokenów przez klienta, który nikogo o nic nie pyta. Patrz na oba pola.

Pobranie listy

Poniższy fragment czyta tenanta i zapisuje CSV. Niczego nie zmienia:

Connect-MgGraph -Scopes 'User.Read.All','AuditLog.Read.All','Group.Read.All'

$guests = Get-MgUser -All -Filter "userType eq 'Guest'" -Property @(
    'id','displayName','userPrincipalName','createdDateTime',
    'accountEnabled','externalUserState','signInActivity'
)

$guests | Select-Object DisplayName, UserPrincipalName, AccountEnabled, ExternalUserState,
    @{ n = 'LastSignIn';   e = { $_.SignInActivity.LastSignInDateTime } },
    @{ n = 'LastNonInter'; e = { $_.SignInActivity.LastNonInteractiveSignInDateTime } },
    @{ n = 'DaysInactive'; e = {
        if ($_.SignInActivity.LastSignInDateTime) {
            [int](New-TimeSpan -Start $_.SignInActivity.LastSignInDateTime -End (Get-Date)).TotalDays
        }
    } } |
    Sort-Object DaysInactive -Descending |
    Export-Csv .\guests.csv -NoTypeInformation -Encoding UTF8

Jeśli Twój tenant odrzuci to połączenie -Filter z signInActivity, pomiń filtr i wybierz konta po stronie PowerShella przez $_.UserType -eq 'Guest'. Na dużym katalogu jest wolniej, ale działa zawsze.

Dlaczego „rok bez logowania" to nie wyrok

Liczba dni jest przesłanką do decyzji, a nie decyzją. Zanim uznasz konto gościnne za zbędne, trzy grupy zasługują na drugie spojrzenie:

  • Rzadko, ale celowo. Audytorzy zewnętrzni, członkowie rady, awaryjne konta partnerskie — używane raz w roku, świadomie, i boleśnie brakujące dokładnie w najgorszym momencie.
  • Nieprzyjęte zaproszenia. Konto z externalUserState równym PendingAcceptance nigdy się nie zalogowało z definicji. Ono nie jest nieaktywne — ono nigdy nie zostało aktywowane. To inny problem i inne rozwiązanie.
  • Goście z rolami. Zewnętrznej tożsamości z przypisaną rolą administracyjną nie usuwa się przy okazji rutynowego sprzątania. Takie konta znajdź najpierw i potraktuj indywidualnie.

Drugim sygnałem, który warto pobrać, jest członkostwo w grupach. Gość należący wyłącznie do domyślnej grupy All Guest Users to zupełnie inna sytuacja niż taki, który siedzi w grupie dającej dostęp do działającej aplikacji.

Kolejność, która wytrzymuje zderzenie z rzeczywistością

Bezpieczny wzorzec to nie „skanuj i usuwaj", tylko:

  1. Raport. Przygotuj listę i pokaż ją osobom, które odpowiadają za relację — kierownicy projektów wiedzą rzeczy, których katalog nie wie.
  2. Blokada. Wyłącz konto, zamiast je usuwać. Wyłączenie jest natychmiast odwracalne i samo wyławia konta, które komuś jednak były potrzebne: reklamacja przychodzi w ciągu tygodnia.
  3. Czekanie. Daj okres karencji. Trzydzieści dni łapie procesy miesięczne, kwartał łapie kwartalne.
  4. Usunięcie. Dopiero wtedy i tylko dla kont, które przez całe okno milczały.

Jednej rzeczy Entra ID za Ciebie nie zrobi: nie zapisuje, kiedy konto zostało wyłączone. Katalog wie, że konto jest zablokowane, a nie od kiedy. Jeśli Twój okres karencji ma cokolwiek znaczyć, tę datę musisz śledzić sam — w pliku, w arkuszu albo w atrybucie rozszerzenia na koncie.

Zabezpiecz wyjątki systemowo

W każdym tenancie są konta, których nie wolno tknąć, a pamiętanie o nich nie jest strategią. Zapisz wyjątek zamiast go pamiętać: dedykowana grupa wykluczeń albo atrybut rozszerzenia w rodzaju extensionAttribute15 = DoNotDelete ustawiony na koncie. Reguła staje się wtedy mechaniczna, przeżywa osobę, która ją wymyśliła, i działa tak samo przy dziesiątym sprzątaniu jak przy pierwszym.

Usunięcie jest mniej ostateczne, niż się wydaje

Usunięcie użytkownika w Entra ID to usunięcie miękkie. Konto trafia do kosza i pozostaje odzyskiwalne przez 30 dni, z portalu albo poleceniem Restore-MgDirectoryDeletedItem. To realna siatka bezpieczeństwa — ale trzydziestodniowa i nie przywracająca wszystkiego idealnie, więc powinna być zabezpieczeniem, a nie planem.

Kiedy robisz to cyklicznie

Powyższy skrypt wystarcza na jeden raz. Kłopot zaczyna się przy drugim przebiegu, kiedy trzeba pamiętać, które konta zablokowałeś w zeszłym kwartale, które są w okresie karencji, które są wyłączone z reguł, a które wróciły do życia. Ten stan nie mieszka w katalogu, a arkusz kalkulacyjny starzeje się źle.

Tę lukę wypełnia Guest Account Cleanup: ten sam skan tylko do odczytu, plus daty blokad, reguły wykluczeń i arytmetyka okresu karencji trzymane w jednym miejscu — z trybem próbnym włączonym domyślnie, więc nic się nie zmienia, dopóki sam nie zdecydujesz.

Sprzątasz katalog, który odziedziczyłeś?

Napisz, z iloma kontami gościnnymi mniej więcej masz do czynienia, a przeprowadzimy Cię przez to. Sam skan jest tylko do odczytu.

Skontaktuj się