Per trovare gli utenti Microsoft 365 inattivi, unite due elementi che restano in punti separati: le licenze assegnate a ciascun account e la data dell'ultimo accesso riuscito di quell'account. Microsoft Graph conserva entrambi sull'oggetto utente, quindi una sola chiamata Get-MgUser che seleziona assignedLicenses e signInActivity vi restituisce una riga per ogni account con licenza, con la sua data di ultimo accesso. Confrontate quelle righe con una soglia che il vostro team concorda in anticipo, di solito 30, 60 o 90 giorni, e ogni account oltre la linea è una postazione a pagamento senza alcuna prova di utilizzo alle spalle. Lo script qui sotto fa esattamente questo e scrive un CSV che potete portare in revisione. Copiatelo, eseguitelo, tenetelo.

Questo è il versante degli accessi nello spreco di licenze. La guida complementare su come trovare le licenze Microsoft 365 inutilizzate copre l'altro versante, il divario tra ciò che avete acquistato e ciò che avete assegnato. Quel divario è il più semplice. Questo, la postazione assegnata a un account reale che nessuno utilizza, di solito è il numero più grande e la conversazione più difficile.

Partite dall'aritmetica, perché decide se la cosa vale un pomeriggio

Fate prima il conto, con i vostri numeri anziché con il parametro di riferimento di qualcun altro. Su un ambiente da 300 utenti, se il 4 per cento degli account con licenza non effettua un accesso da un trimestre, sono 12 postazioni. Dodici postazioni a quanto pagate davvero per utente al mese, moltiplicate per dodici mesi, danno la cifra annuale. A £20 a postazione fanno £2,880 all'anno; a £30 fanno £4,320. Cambiate un qualsiasi dato di partenza e la risposta si sposta, ed è proprio questo il punto: potete verificarlo a mente, e può farlo anche il vostro responsabile finanziario.

Due cose rendono la cosa degna di attenzione in un'organizzazione da 50 a 600 utenti. Si ripete ogni mese finché qualcuno non interviene, quindi non fare nulla si accumula. E non è quasi mai il compito di nessuno. La finanza vede una fattura stabile e presume che sia corretta; l'IT vede un conteggio di licenze e presume che la finanza lo abbia approvato. È così che le postazioni dormienti sopravvivono per anni.

Perché la pagina Licenses non può rispondere a questa domanda

La prima tappa ovvia è l'interfaccia di amministrazione di Microsoft 365, sotto Billing e poi Licenses, che mostra ogni prodotto con quante postazioni avete acquistato e quante sono assegnate. È un controllo utile di due minuti e vale la pena farlo. Notate che aggrega per prodotto, mentre Billing e poi Your products elenca una riga per sottoscrizione, quindi le due pagine non sempre coincidono a colpo d'occhio.

Ciò che nessuna delle due vi dirà è se una postazione assegnata stia facendo qualcosa. Quelle pagine sono costruite attorno al diritto d'uso, non al comportamento. Un account creato per un collaboratore esterno due anni fa, ancora abilitato, che detiene ancora una postazione completa e senza accessi da allora, lì appare identico al vostro utente più impegnato.

Reports e poi Usage vi avvicina. Il report Active users mostra una data di ultima attività per carico di lavoro per Exchange, OneDrive, SharePoint e Teams, insieme alle licenze assegnate. Vale la pena conoscerlo, e risponde a una domanda diversa: se qualcuno ha toccato un'app, non se l'identità si è autenticata. Due cose da mettere in conto. I dati sono generalmente disponibili sugli ultimi 7, 30, 90 e 180 giorni e possono richiedere un giorno o più per comparire. E i nomi utente sono nascosti per impostazione predefinita, quindi se il report mostra righe anonimizzate un amministratore deve togliere l'opzione «Conceal user, group, and site names in all reports» sotto Settings, Org Settings, Services, Reports.

Concordate cosa significa inattivo prima di eseguire qualsiasi cosa

Questo è il passo che i team saltano, ed è quello che decide se il vostro report sopravvive al contatto con il resto dell'azienda. Trenta giorni è aggressivo e raccoglie congedi parentali, assenze per malattia prolungate, aspettative e personale stagionale. Novanta giorni lascia scorrere un trimestre intero di spreco prima che qualcosa venga segnalato. Sessanta è un primo passaggio ragionevole in un ambiente di medie dimensioni. Non esiste una risposta corretta, e chiunque vi dica il contrario, fornitori compresi, vi sta vendendo la propria impostazione predefinita.

Ciò che conta è che la soglia sia una politica scritta di cui il vostro team è responsabile, con eccezioni nominate, prima che il primo report arrivi a chiunque. Un report senza una soglia concordata produce una discussione. Un report che ne ha una produce azioni.

I dati di accesso dietro alla risposta

Microsoft Entra ID registra l'attività di accesso su ogni oggetto utente, e Graph la espone sulla risorsa user della v1.0 come proprietà signInActivity. Contiene un ultimo accesso interattivo, un ultimo accesso non interattivo e un ultimo accesso riuscito, ciascuno abbinato a un ID di richiesta. Interattivo significa che una persona ha digitato le credenziali o approvato una richiesta. Non interattivo copre un client che rinnova un token in background, ed è per questo che un account può sembrare attivo in un campo e spento in un altro.

Il motivo per usare questo dato anziché setacciare i log degli accessi è la conservazione. I log di accesso e di audit sono conservati per 7 giorni nel piano gratuito e 30 giorni con Entra ID P1 o P2, quindi il log da solo non può dirvi nulla su un intervallo di 90 giorni. La proprietà signInActivity è diversa: Entra la conserva per tutto il tempo in cui esiste l'oggetto utente. È la fonte giusta per questa domanda.

Quattro vincoli pratici prima di eseguire qualsiasi cosa:

  • Viene restituita solo se la selezionate esplicitamente. Un Get-MgUser semplice non la include, e la proprietà risulta semplicemente assente anziché generare un errore, che è il motivo più comune per cui si conclude che il dato manchi.
  • Leggerla richiede AuditLog.Read.All insieme a User.Read.All. Senza l'ambito di audit i dati delle licenze arrivano e il campo dell'accesso torna vuoto, il che fa sembrare che ogni account sia inattivo.
  • Richiede Microsoft Entra ID P1 o P2. In un tenant che non ne dispone, aspettatevi che la proprietà non sia disponibile, quindi verificatelo prima di mettervi a fare debug su una colonna vuota.
  • Un valore vuoto non è la prova del mancato utilizzo. L'ultimo accesso riuscito viene registrato solo da dicembre 2023 e non è stato compilato retroattivamente, e il valore può avere un ritardo fino a 24 ore. Trattate il vuoto come «da approfondire», mai come «da eliminare».

Sul fronte della directory non serve il ruolo Global Administrator. Reports Reader è il ruolo con meno privilegi in grado di leggere i log di audit e di accesso, ed è quello giusto da usare: questa è un'attività di reporting e non dovrebbe essere il motivo per cui qualcuno detiene un ruolo di scrittura.

Lo script

Questo è tutto. Si connette, costruisce una tabella di corrispondenza perché l'output riporti i nomi dei piani anziché i GUID, estrae ogni account con licenza insieme alla sua attività di accesso, lo confronta con la vostra soglia e scrive un CSV.

# Inactive licensed users report
# Requires the Microsoft.Graph PowerShell SDK
Connect-MgGraph -Scopes "User.Read.All","AuditLog.Read.All","Organization.Read.All"
$InactiveDays = 60
$Cutoff = (Get-Date).AddDays(-$InactiveDays)
# Map SKU GUIDs to readable plan names
$SkuMap = @{}
Get-MgSubscribedSku | ForEach-Object { $SkuMap[$_.SkuId] = $_.SkuPartNumber }
# signInActivity is only returned when explicitly selected
$Users = Get-MgUser -All -Property "id,displayName,userPrincipalName,accountEnabled,userType,createdDateTime,assignedLicenses,signInActivity"
$Report = foreach ($u in $Users) {
    if (-not $u.AssignedLicenses -or $u.AssignedLicenses.Count -eq 0) { continue }
    if ($u.UserType -eq 'Guest') { continue }
    $last = $u.SignInActivity.LastSuccessfulSignInDateTime
    if (-not $last) { $last = $u.SignInActivity.LastSignInDateTime }
    if ($last -and $last -ge $Cutoff) { continue }
    [pscustomobject]@{
        DisplayName       = $u.DisplayName
        UserPrincipalName = $u.UserPrincipalName
        Enabled           = $u.AccountEnabled
        Created           = $u.CreatedDateTime
        LastSignIn        = $last
        DaysSinceSignIn   = if ($last) { [int](New-TimeSpan -Start $last -End (Get-Date)).TotalDays } else { 'Never' }
        Licences          = (($u.AssignedLicenses.SkuId | ForEach-Object { $SkuMap[$_] }) -join '; ')
    }
}
$Report | Sort-Object Created |
    Export-Csv -Path ".\inactive-licensed-users.csv" -NoTypeInformation -Encoding UTF8
"{0} licensed accounts with no sign-in in {1} days" -f @($Report).Count, $InactiveDays

Leggetelo una volta prima di eseguirlo. Salta gli account senza licenza, perché un account dormiente senza licenza non costa nulla, e salta gli utenti guest, perché seguono regole diverse e altrimenti dominerebbero l'output. Preferisce l'ultimo accesso riuscito e ripiega sull'ultimo accesso interattivo, così si comporta in modo sensato sugli account il cui accesso riuscito precede l'avvio di quel campo a dicembre 2023. Confronta le righe con la soglia in PowerShell anziché nella query Graph: signInActivity può essere filtrata lato server, ma non in combinazione con un'altra proprietà filtrabile, quindi farlo lato client tiene le condizioni su licenza e guest nello stesso punto. Un account che non ha mai effettuato l'accesso compare come Never anziché come valore vuoto, perché è un esito diverso da quello di un account dormiente da tempo.

Il ciclo in quattro mosse. Lo script copre le prime due. Le ultime due sono giudizio, ed è lì che il denaro si muove davvero.

Cosa emerge di solito dal report, e la decisione che ogni caso richiede

Quasi ogni primo passaggio produce le stesse quattro categorie, e ognuna richiede una decisione diversa da una persona diversa.

Chi ha lasciato l'azienda senza un offboarding completo. Un account ancora abilitato, ancora con licenza, a volte mesi dopo l'uscita della persona. È l'esito di maggior valore e minor rischio, ed è un fallimento di processo più che di licenze. Rimuovete la licenza, bloccate l'accesso e gestite correttamente la casella di posta e i file. La checklist di offboarding Microsoft 365 riporta l'ordine completo delle operazioni, il che conta perché eseguire questi passaggi nella sequenza sbagliata comporta la perdita di dati.

Account di servizio e condivisi che occupano postazioni complete. Spesso non mostrano alcun accesso interattivo pur essendo realmente utilizzati da un'applicazione. Non toccateli finché non avete trovato il responsabile. Chiedete di cosa abbia davvero bisogno l'account, perché una postazione di produttività completa è spesso molto più della risposta.

Componenti aggiuntivi duplicati o sovrapposti. Account che portano un componente aggiuntivo già incluso in un piano base più recente. L'account è attivo, quindi non compare mai come dormiente, ma il componente aggiuntivo è peso morto. Ordinare l'output per la colonna delle licenze li fa emergere in fretta.

Persone reali davvero inattive. Qualcuno in congedo prolungato, qualcuno che ha cambiato ruolo, qualcuno inserito su un piano che non ha mai usato. È la categoria che richiede un responsabile nella conversazione anziché uno script, e l'esito è spesso un declassamento più che una rimozione. La nostra guida a Business Premium, E3 ed E5 è un riferimento utile per capire quanto costa davvero all'utente un piano più leggero.

Un avvertimento prima di agire su tutto questo. Verificate da dove proviene ogni licenza prima di toglierla all'utente. Le assegnazioni basate sui gruppi si gestiscono a livello di gruppo, e la pagina Licenses mostra il nome del gruppo anziché i suoi membri, quindi una postazione che rimuovete da un account può tornare silenziosamente attraverso l'appartenenza al gruppo e il risparmio non raggiunge mai la fattura.

Se le quattro categorie qui sopra vi suonano già familiari, potete vedere lo stesso report girare in continuo sul vostro tenant con una prova EtherInsights di 14 giorni, senza manutenzione di script.

Il limite onesto di eseguirlo come script

Lo script è buono. È anche un'istantanea, e questo è il suo tetto. Qualcuno deve ricordarsi di eseguirlo. Qualcuno deve interpretarlo, perché un CSV con 40 account non è una decisione, sono 40 decisioni. Qualcuno deve sollecitare i responsabili, applicare le modifiche e poi dimostrare alla finanza che il numero di postazioni è davvero sceso al rinnovo, che è di nuovo un lavoro a parte. Saltate due mesi e l'ambiente si è mosso sotto di voi.

Non è un argomento contro lo scripting. Eseguitelo comunque questa settimana. È un argomento per essere lucidi sul quarto mese, quando chi lo ha scritto è occupato e il report smette silenziosamente di essere eseguito. In un'organizzazione da 50 a 600 utenti il vincolo raramente è la capacità. È che nessuno è responsabile dell'attività ricorrente.

Dove si inserisce EtherInsights

EtherInsights è la versione continua di ciò che questo script fa una volta sola. Riconcilia le licenze con l'attività reale a cadenza pianificata, fa emergere le postazioni dormienti e mai usate come constatazioni con un responsabile nominato e un'azione successiva anziché come un foglio di calcolo, e traccia il prima e il dopo perché un recupero arrivi alla vostra revisione finanziaria come evidenza anziché come affermazione. Per l'intero ciclo di vita, da una postazione dormiente segnalata fino all'offboarding di chi lascia l'azienda prima che la sua licenza generi di nuovo costi, la gestione delle licenze e l'offboarding di Microsoft 365 è il percorso che chiude il cerchio.

Costa £0.79 per utente attivo con una prova di 14 giorni, quindi potete applicare l'aritmetica dell'inizio di questo articolo al vostro tenant prima di impegnarvi. Se dovete portare a chi gestisce il budget un numero anziché un metodo, di solito è il modo più rapido per ottenerlo. Lo spreco di licenze è una voce in un quadro più ampio, ed è per questo che rientra nell'ottimizzazione dei costi cloud, e perché dimostrare il risparmio conta quanto trovarlo.

Concordate la soglia, eseguite lo script, agite subito su chi ha lasciato l'azienda e fissate una data in calendario per il mese prossimo. Se quella data continua a slittare, avete trovato il vero problema, e non è tecnico.

Esplora la gestione delle licenze e l'offboarding di Microsoft 365 per vedere le postazioni dormienti, l'offboarding di chi lascia l'azienda e la traccia delle evidenze gestiti come un unico processo continuo anziché come un promemoria mensile.