Punti chiave
- Individua il rischio: interroga la Microsoft Graph API con PowerShell per identificare le licenze Microsoft 365 scadute e gli account Azure AD inattivi da oltre 90 giorni.
- Prevedi gli accessi corretti: configura un ruolo Amministratore globale o Lettore di report, il Microsoft Graph PowerShell SDK e le autorizzazioni User.Read.All, LicenseAssignment.ReadWrite.All e AuditLog.Read.All prima di eseguire i controlli.
- Esporta e archivia i risultati: salva i dati raccolti in report CSV con marca temporale per mantenere una traccia di audit utile alla conformità e alle decisioni di recupero delle licenze.
- Automatizza la pianificazione: esegui lo script a intervalli regolari con l’Utilità di pianificazione di Windows su una singola macchina, oppure distribuiscilo su più endpoint e tenant tramite uno strumento RMM.
- Escludi e calibra: inserisci in whitelist gli account di servizio e quelli di emergenza (break-glass) e imposta soglie di inattività coerenti con la tolleranza al rischio della tua organizzazione.
Le licenze Microsoft 365 inutilizzate erodono silenziosamente il budget, mentre gli account Azure AD inattivi rappresentano un rischio concreto per la sicurezza. Automatizza i controlli con la Microsoft Graph API per individuare licenze scadute e account dormienti prima che si traducano in spese inutili o falle di sicurezza.
In questa guida ti mostriamo come pianificare controlli critici tramite PowerShell per chiudere le vulnerabilità e scalare su più clienti.
Per una panoramica visiva rapida, guarda la nostra video guida su Come eseguire controlli Graph API pianificati per licenze scadute e utenti inattivi.
Procedura passo passo per pianificare i controlli Graph API con PowerShell
Automatizza i controlli Graph API per recuperare le licenze sprecate, mettere in sicurezza gli account dormienti, rispettare la conformità e semplificare la gestione dei tenant: tutto in un’unica passata.
Situazione d’uso: usa questo metodo durante le revisioni mensili dei costi, gli audit di sicurezza o prima dei rinnovi delle licenze. È ideale per gli MSP che recuperano licenze Office 365 scadute o che applicano l’hardening della sicurezza dopo l’offboarding di un dipendente. Ti aiuta inoltre a individuare gli utenti inattivi prima che diventino vulnerabilità per il tuo sistema.
Prerequisiti: prima di procedere con la procedura, assicurati di avere quanto segue:
- Autorizzazioni amministrative: verifica che il tuo account disponga del ruolo Amministratore globale o Lettore di report in Azure AD.
- Strumenti: Microsoft Graph PowerShell SDK (modulo Microsoft.Graph) e PowerShell 7+.
- Configurazione di Azure: assicurati che la tua app Azure AD disponga delle autorizzazioni User.Read.All, LicenseAssignment.ReadWrite.All e AuditLog.Read.All per l’automazione.
- Facoltativo ma consigliato: scarica e installa uno strumento RMM come NinjaOne per pianificare gli script, monitorarne gli output e scalare su più tenant.
Passaggio 1: installa e autentica il Microsoft Graph SDK
Prepara gli strumenti necessari per automatizzare i controlli su licenze e utenti. L’installazione del Graph SDK, che consente di interrogare i dati di Azure AD normalmente nascosti dall’amministratore, collega il tuo script all’API di Microsoft tramite autenticazione.
Procedura passo passo:
- Installa l’SDK eseguendo questo script in PowerShell (Admin) o Windows Terminal (Admin):
Install-Module Microsoft.Graph -Scope CurrentUser -Force
- Autenticati con questo script:
Connect-MgGraph -Scopes "User.Read.All", "LicenseAssignment.ReadWrite.All", "AuditLog.Read.All
Puoi anche configurare un’app registrata con un client secret e usare il flusso con certificato o con credenziali client per l’esecuzione non presidiata.
Una volta autenticato il Graph SDK, nei passaggi successivi potrai interrogare gli utenti Azure AD inattivi e le licenze Office 365 scadute.
Passaggio 2: individua gli utenti con licenze scadute o non assegnate
Questo passaggio ti aiuta a far emergere licenze scadute e account inattivi che comportano rischi per la sicurezza e costi superflui.
Procedura passo passo:
- In PowerShell (Admin), esegui questo script per verificare le licenze non assegnate a livello di tenant:
Get-MgSubscribedSku |
Select-Object SkuPartNumber,
@{Name="TotalLicenses"; Expression={$_.PrepaidUnits.Enabled}},
@{Name="UsedLicenses"; Expression={$_.ConsumedUnits}},
@{Name="Available"; Expression={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} |
Format-Table -AutoSize
- Esegui questo script per trovare gli utenti senza licenza:
Get-MgUser -Filter "assignedLicenses/`$count eq 0" `
-ConsistencyLevel eventual `
-CountVariable unlicensedCount `
-All |
Select-Object DisplayName, UserPrincipalName |
Export-Csv -Path "UnlicensedUsers.csv" -NoTypeInformation
- Esegui questo script per trovare gli utenti inattivi con licenza:
$daysInactive = 90
$cutoffDate = (Get-Date).AddDays(-$daysInactive)# Get licensed inactive users
Get-MgUser -All -Property "DisplayName,UserPrincipalName,SignInActivity,AssignedLicenses" |
Where-Object {
($_.SignInActivity.LastSignInDateTime -lt $cutoffDate) -and
($_.AssignedLicenses.Count -gt 0)
} |
Select-Object DisplayName,
UserPrincipalName,
@{Name="LastSignIn"; Expression={$_.SignInActivity.LastSignInDateTime}} |
Export-Csv -Path "InactiveLicensedUsers.csv" -NoTypeInformation
Importante: tieni presente che SignInActivity richiede Azure AD Premium P1/P2. Evita inoltre gli endpoint beta negli script di produzione.
Dopo aver eseguito questi script otterrai due file CSV: UnlicensedUsers.csv, che contiene gli utenti a cui assegnare una licenza, e InactiveLicensedUsers.csv, che elenca gli account che costituiscono un rischio per la sicurezza.
Passaggio 3: esporta e registra i risultati dell’audit
Una volta ottenuto l’elenco delle licenze scadute e non assegnate, trasforma questi dati in informazioni utili con un reporting automatizzato. L’esportazione crea tracce di audit permanenti a prova di conformità e l’automazione ti garantisce di intercettare i problemi prima che diventino costosi.
Procedura passo passo:
- In PowerShell (Admin), esegui questo script per esportare in un CSV con marca temporale:
- Script per generare un nome file con marca temporale:
$timestamp = Get-Date -Format "yyyyMMdd-HHmm"
$reportPath = "C:\Audits\LicenseReport_$timestamp.csv"
-
- Esporta gli utenti inattivi con licenza:
$inactiveUsers | Export-Csv -Path $reportPath -NoTypeInformation
-
- In questo modo otterrai file CSV apribili ovunque e la marca temporale creerà record versionati ai fini della conformità.
- (Facoltativo): esegui questo script per inviare i report via email:
Send-MailMessage -From "[email protected]" -To "[email protected]" `
-Subject "ACTION REQUIRED: $($inactiveUsers.Count) Inactive Licensed Users" `
-Body "Attached: Users with licenses but no sign-ins for 90+ days" `
-Attachments $reportPath -SmtpServer "smtp.office365.com" -Port 587 `
-Credential (Get-Credential)
- Esegui questo script per automatizzare completamente il processo con l’app Azure AD:
$tenantId = "YOUR_TENANT_ID"
$clientId = "YOUR_CLIENT_ID"
$clientSecret = "YOUR_SECRET" | ConvertTo-SecureString -AsPlainText -ForceConnect-MgGraph -TenantId $tenantId -ClientId $clientId -ClientSecret $clientSecret
Suggerimento: conserva i segreti in Azure Key Vault. Non inserirli mai direttamente nel codice.
Dopo aver eseguito questi script avrai report CSV con marca temporale salvati in locale e, se vuoi, avvisi via email immediati per le parti interessate. Questi file ti permettono di impostare esecuzioni automatizzate tramite l’Utilità di pianificazione o strumenti RMM come NinjaOne, così da garantire un monitoraggio continuo.
Passaggio 4: automatizza con l’Utilità di pianificazione o una policy RMM
Pianifica lo script una sola volta e lascialo girare ogni mese, ogni anno o all’infinito: avrai un monitoraggio proattivo senza muovere un dito. Controlli regolari aiutano a intercettare le anomalie prima che diventino problemi. Ci sono due modi per farlo:
Opzione 1: con l’Utilità di pianificazione (singola macchina)
Procedura passo passo:
- Apri il Prompt dei comandi (Admin), quindi esegui questo comando:
schtasks /create /tn "M365LicenseAudit" /tr `
"powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\LicenseAudit.ps1" `
/sc weekly /d MON /st 02:00 /ru "NT AUTHORITY\SYSTEM"
-
- Questo approccio funziona perché l’esecuzione avviene con un account di sistema anche quando nessun utente ha effettuato l’accesso.
Opzione 2: con strumenti RMM
Procedura passo passo:
- Apri lo strumento RMM che preferisci, ad esempio NinjaOne.
- Crea lo script (quello dell’Opzione 1) e salvalo nella libreria di script di NinjaOne.
- Assegna lo script al gruppo di policy Microsoft 365 Clients.
- Configura gli output:
- Salva i CSV in \\ClientShare\Audits.
- Caricali nella dashboard dell’RMM per una visualizzazione centralizzata.
Una volta pianificato, lo script verrà eseguito nella data e nell’ora assegnate, salvando automaticamente i report nelle cartelle designate e mostrando gli andamenti tra i vari tenant.
Aspetti a cui prestare attenzione
Questa sezione evidenzia le possibili difficoltà da tenere a mente mentre segui la guida.
| Rischi | Possibili conseguenze | Rimedi |
| 1. Dati mancanti nei report | Audit incompleti, rischi non rilevati | Controlla le autorizzazioni: esegui Get-MgContext per verificare ambiti come User.Read.All.
Aggira i blocchi MFA: usa l’autenticazione con certificato invece dei segreti. |
| 2. Lo script fallisce senza segnalarlo | Falso senso di sicurezza, lacune di conformità | Attiva la registrazione: aggiungi Start-Transcript -Path C:\Logs\Audit.log agli script.
Monitora il Visualizzatore eventi: controlla in Registri applicazioni e servizi > PowerShell. |
| 3. Utenti non segnalati | Licenze scadute/account inattivi non rilevati | Verifica le soglie: conferma che $cutoffDate sia coerente con la policy.
Verifica i campi delle licenze: usa |
| 4. Segreti inseriti direttamente nel codice | Compromissione del tenant, furto di credenziali | Ruota subito i segreti in Azure AD.
Passa ad Azure Key Vault: usa Get-AzKeyVaultSecret per recuperare i segreti in modo sicuro. |
| 5. Dipendenza dalle API beta | Lo script smette di funzionare dopo gli aggiornamenti Microsoft | Sostituisci gli endpoint beta: usa Get-MgUser (v1.0) al posto di Get-MgBetaUser.
Iscriviti al changelog di Microsoft Graph. |
Considerazioni chiave per audit PowerShell con Graph API a prova di errore
Adatta queste impostazioni al tuo ambiente. La precisione evita i falsi allarmi e mantiene fluidi i flussi di lavoro.
Esclusioni dai report
Escludi dalle scansioni di inattività gli account di servizio, le cassette postali condivise e gli account di emergenza (break-glass). In questo modo eviti di recuperare per errore licenze legate a risorse critiche. Puoi inserirli in whitelist con i filtri di PowerShell, usando questo script:
$excludedUPNs = @("[email protected]", "[email protected]")
Get-MgUser | Where-Object { $_.UserPrincipalName -notin $excludedUPNs }
Soglie di inattività
Imposta le soglie in base alla tua tolleranza al rischio. Un account inattivo da 90 giorni è a rischio basso, 60 giorni corrispondono a un rischio medio e 30 giorni a un rischio elevato. In base al livello di rischio puoi intervenire inviando email di avviso, revocando le licenze oppure disabilitando l’account e recuperando la licenza. Così resti al riparo dai problemi.
Frequenza degli audit
Scegli il momento giusto per gli audit, così da evitare rischi di sicurezza e altri inconvenienti. Per la maggior parte delle aziende si consigliano controlli mensili, allineati ai cicli di fatturazione.
Nei settori con un ricambio elevato, controlli settimanali permettono ai report di stare al passo con i cambiamenti dell’ambiente. È inoltre opportuno avviare subito un audit a ogni uscita di un dipendente dall’azienda.
Mappatura delle azioni
Crea procedure operative standard che attivino automaticamente i passaggi successivi. Esegui gli script seguenti per recuperare le licenze e disabilitare gli account:
- Per recuperare le licenze:
Set-MgUserLicense -UserId "[email protected]" -RemoveLicenses @("skuId")
- Per disabilitare gli account:
Update-MgUser -UserId "[email protected]" -AccountEnabled:$false
Dopo aver eseguito questi script, archivia i dati. Inoltrali al responsabile o a SharePoint tramite la Graph API.
Come NinjaOne semplifica gli audit delle licenze
Trasforma i controlli Graph API da attività manuali a motori di conformità completamente automatizzati e multi-tenant.
- Distribuzione centralizzata degli script: invia i tuoi script PowerShell per la Graph API a oltre 100 endpoint/tenant con una sola operazione.
- Monitoraggio automatico degli output: tieni traccia di report CSV e log su tutti i clienti. Gli avvisi scattano all’istante se i file non si aggiornano.
- Avvisi di errore nei tuoi strumenti: ricevi notifiche su Slack, Teams o via email quando uno script fallisce.
- Report unificati su più tenant: unisci i dati su licenze Office 365 scadute e utenti inattivi in un’unica dashboard per la direzione.
- Remediation automatica: crea automaticamente ticket nel tuo strumento PSA usando procedure operative standard predefinite per rilevare le licenze scadute.
Tieni sotto controllo costi e sicurezza con i controlli delle licenze via Graph API
Automatizzare gli audit di licenze e utenti trasforma una supervisione reattiva in un controllo proattivo. Recuperando le licenze inutilizzate e disabilitando gli account dormienti, eviti perdite di budget e chiudi possibili vettori di attacco. Segui la procedura descritta sopra per convertire le licenze inutilizzate in risparmio e gli account obsoleti in conformità.
Guida rapida
NinjaOne ti aiuta a eseguire controlli Graph API pianificati per licenze scadute e utenti inattivi. La piattaforma NinjaOne offre strumenti e indicazioni per:
- Verificare le licenze scadute: usa la Graph API per individuare le licenze che hanno superato la data di scadenza
- Controllare gli utenti inattivi: individua gli utenti che non hanno effettuato l’accesso o utilizzato i servizi entro un periodo definito
- Automatizzare questi controlli: imposta attività pianificate per eseguire regolarmente questi audit
Argomenti correlati
- 8 best practice per la sicurezza delle API
- Come segnalare gli account utente inattivi in Linux: guida completa agli script
- Automatizza il rilevamento degli account utente inattivi con PowerShell
- Come identificare e gestire gli account locali inutilizzati nei sistemi Windows
- Guida completa alla disabilitazione degli account utente in Linux per professionisti IT