Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Windows & Microsoft 365 04.06.2026 · 10 min Lesezeit

Microsoft-365-Lizenzen optimieren: ungenutzte Lizenzen aufspüren und Kosten senken (mit PowerShell)

Wie Sie mit dem Microsoft Graph PowerShell SDK ungenutzte Microsoft-365-Lizenzen finden: inaktive und deaktivierte Konten, lizenzierte Shared Mailboxen, Mehrfachzuweisungen und E5-Downgrade-Kandidaten, mit sicherem Entfernen ohne Datenverlust.

Geprüft am 30.09.2026

Mehrere zugeklappte Laptops mit grünen und grauen Anhängern neben einem weißen Sparschwein auf hellem Holztisch

In vielen Microsoft-365-Tenants belegen ausgeschiedene Mitarbeitende, deaktivierte Konten oder Shared Mailboxen weiterhin Lizenzen. Diese Anleitung zeigt, wie Sie mit dem Microsoft Graph PowerShell SDK einen Lizenz-Report erstellen, ungenutzte Lizenzen finden und sauber entfernen, ohne Postfachdaten zu verlieren.

Voraussetzungen

  • Microsoft-365-Tenant; Rolle Globaler Leser für die Reports, Lizenzadministrator bzw. Benutzeradministrator für Änderungen
  • Microsoft Entra ID P1 oder P2 im Tenant (in Microsoft 365 Business Premium, E3 und E5 enthalten): Ohne P1 liefert Graph keine Anmeldeaktivität (signInActivity) für Schritt 3
  • PowerShell 7.x (empfohlen) oder Windows PowerShell 5.1
  • Microsoft Graph PowerShell SDK: Install-Module Microsoft.Graph -Scope CurrentUser
  • Exchange Online Management Modul (für Shared-Mailbox-Abfragen): Install-Module ExchangeOnlineManagement
  • Ausgabepfad C:\Reports\ muss existieren und Schreibrechte besitzen
  • Für unbeaufsichtigte Ausführung: App-Registrierung in Entra ID mit Client-Secret oder Zertifikat sowie den Graph-Anwendungsberechtigungen User.Read.All, Organization.Read.All und AuditLog.Read.All

Schritt 1: Verbindung herstellen und Module prüfen

Stellen Sie sicher, dass die Module in aktueller Version installiert sind. MSOnline funktioniert seit 2025 nicht mehr, AzureAD ist ebenfalls eingestellt; verwenden Sie beide nicht mehr.

# Module aktualisieren
Update-Module Microsoft.Graph -Scope CurrentUser
Update-Module ExchangeOnlineManagement -Scope CurrentUser

# Interaktive Anmeldung (MFA-fähig)
Connect-MgGraph -Scopes 'User.Read.All', 'Organization.Read.All', 'AuditLog.Read.All'

# Ausgabepfad anlegen, falls nicht vorhanden
if (-not (Test-Path 'C:\Reports')) { New-Item -ItemType Directory -Path 'C:\Reports' }

Verifizieren: Get-MgContext | Select-Object Account, Scopes zeigt Ihr Konto und die drei Scopes. Fehlt ein Scope, melden Sie sich mit Disconnect-MgGraph ab und erneut an; beim ersten Mal ist eine Administratorzustimmung nötig.

Schritt 2: Gebuchte SKUs und freie Lizenzen überblicken

Die Differenz zwischen PrepaidUnits.Enabled (bezahlte Plätze) und ConsumedUnits (zugewiesene Plätze) ergibt die freien Lizenzen, die Sie bei der nächsten Vertragsanpassung reduzieren können.

# Alle gebuchten SKUs mit freien Lizenzen anzeigen
Get-MgSubscribedSku -All | Select-Object SkuPartNumber, SkuId,
  @{N='Gesamt';E={$_.PrepaidUnits.Enabled}},
  @{N='Verbraucht';E={$_.ConsumedUnits}},
  @{N='Frei';E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}} |
  Sort-Object Frei -Descending | Format-Table -AutoSize

Häufige SKU-Bezeichnungen im Überblick:

SkuPartNumberProdukt
SPE_E3Microsoft 365 E3
SPE_E5Microsoft 365 E5
SPBMicrosoft 365 Business Premium
O365_BUSINESS_PREMIUMMicrosoft 365 Business Standard
O365_BUSINESS_ESSENTIALSMicrosoft 365 Business Basic
ENTERPRISEPACKOffice 365 E3
O365_BUSINESSMicrosoft 365 Apps for Business

Verifizieren: Die Tabelle listet jede gebuchte SKU mit Gesamt-, Verbraucht- und Frei-Wert; die Summen entsprechen der Übersicht im Microsoft 365 Admin Center unter Abrechnung > Lizenzen.

Schritt 3: Inaktive Benutzer mit Lizenzen finden

Als inaktiv gilt ein Konto, das sich seit mehr als 90 Tagen nicht angemeldet hat. Die Eigenschaft SignInActivity muss explizit per -Select angefordert werden und erfordert Entra ID P1 sowie AuditLog.Read.All. Für den $count-Filter sind -ConsistencyLevel eventual und -CountVariable nötig.

# Inaktive Benutzer (>90 Tage keine Anmeldung) mit Lizenzen
$cutoff = (Get-Date).AddDays(-90)
Get-MgUser -Filter 'assignedLicenses/$count ne 0' `
  -ConsistencyLevel eventual -CountVariable anzahl -All `
  -Select UserPrincipalName,DisplayName,AccountEnabled,SignInActivity,AssignedLicenses |
  Where-Object {
    $_.SignInActivity.LastSuccessfulSignInDateTime -lt $cutoff -or
    $_.SignInActivity.LastSuccessfulSignInDateTime -eq $null
  } |
  Select-Object UserPrincipalName, DisplayName, AccountEnabled,
    @{N='LetzteAnmeldung';E={$_.SignInActivity.LastSuccessfulSignInDateTime}} |
  Export-Csv -Path 'C:\Reports\InaktiveLizenzierte.csv' -NoTypeInformation -Encoding UTF8

Ebenfalls schnell zu finden: deaktivierte Konten, die noch eine Lizenz belegen.

# Deaktivierte Konten mit aktiver Lizenz
Get-MgUser -Filter "assignedLicenses/`$count ne 0 and accountEnabled eq false" `
  -ConsistencyLevel eventual -CountVariable anzahl -All `
  -Select UserPrincipalName,DisplayName,AccountEnabled,AssignedLicenses |
  Export-Csv -Path 'C:\Reports\DeaktivierteMitLizenz.csv' -NoTypeInformation -Encoding UTF8

Verifizieren: Ist die Spalte LetzteAnmeldung in InaktiveLizenzierte.csv bei allen Zeilen leer, fehlt Entra ID P1 oder der Scope AuditLog.Read.All. Gleichen Sie Stichproben mit den Anmeldeprotokollen im Entra Admin Center ab.

Schritt 4: Analysieren Sie direkte und gruppenbasierte Lizenzzuweisungen

Lizenzen weisen Sie im Microsoft 365 Admin Center zu; das Entra Admin Center bietet dafür keine Bearbeitung mehr. Über die Graph-Eigenschaft LicenseAssignmentStates erkennen Sie, ob eine Lizenz direkt oder über eine Gruppe vergeben wurde. Sie ist in Graph v1.0 verfügbar, muss aber per -Property angefordert werden.

# Direkte vs. gruppenbasierte Lizenzzuweisung prüfen
Get-MgUser -All `
  -Property UserPrincipalName,DisplayName,LicenseAssignmentStates |
  ForEach-Object {
    $user = $_
    $_.LicenseAssignmentStates | ForEach-Object {
      [PSCustomObject]@{
        UPN           = $user.UserPrincipalName
        SkuId         = $_.SkuId
        ZuweisungsArt = if ($_.AssignedByGroup) { "Gruppe: $($_.AssignedByGroup)" } else { 'Direkt' }
        Fehler        = $_.Error
      }
    }
  } | Export-Csv -Path 'C:\Reports\LizenzZuweisungsPfad.csv' -NoTypeInformation -Encoding UTF8

Anschließend erkennen Sie Mehrfachzuweisungen: Ein Benutzer erhält dieselbe SKU direkt und über eine Gruppe oder über mehrere Gruppen. Er verbraucht dabei nur eine Lizenz, doch das Entfernen aus der Gruppe gibt sie nicht frei. Entfernen Sie die direkte Zuweisung, wenn die Gruppe die Lizenz steuern soll.

# Doppelzuweisungen (Direkt + Gruppe für gleiche SKU) erkennen
$doppelt = Get-MgUser -All -Property UserPrincipalName,LicenseAssignmentStates |
  ForEach-Object {
    $u = $_
    $skus = $_.LicenseAssignmentStates | Group-Object SkuId
    $skus | Where-Object { $_.Count -gt 1 } | ForEach-Object {
      [PSCustomObject]@{ UPN = $u.UserPrincipalName; SkuId = $_.Name; Anzahl = $_.Count }
    }
  }
$doppelt | Export-Csv -Path 'C:\Reports\Doppellizenzen.csv' -NoTypeInformation -Encoding UTF8

Verifizieren: LizenzZuweisungsPfad.csv enthält je Benutzer und SKU eine Zeile mit Direkt oder Gruppe: <ID>. Einträge in der Spalte Fehler ungleich None weisen auf Zuweisungsprobleme hin (siehe Troubleshooting).

Schritt 5: Lizenzierte Shared Mailboxen aufspüren

Freigegebene Postfächer (Shared Mailboxen) benötigen bis 50 GB keine Lizenz. Ausnahmen: Archiv-Postfach, Beweissicherungsverfahren (Litigation Hold) oder mehr als 50 GB erfordern eine Lizenz. Dieser Schritt nutzt Exchange Online und Microsoft Graph.

# Shared Mailboxen mit zugewiesener Lizenz finden
# Erfordert: Connect-ExchangeOnline + Connect-MgGraph
Connect-ExchangeOnline
$sharedMBX = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited |
  Select-Object -ExpandProperty UserPrincipalName
$sharedMBX | ForEach-Object {
  $u = Get-MgUser -UserId $_ -Property UserPrincipalName,DisplayName,AssignedLicenses
  if ($u.AssignedLicenses.Count -gt 0) {
    [PSCustomObject]@{ UPN = $u.UserPrincipalName; Lizenzen = ($u.AssignedLicenses.SkuId -join '; ') }
  }
} | Export-Csv -Path 'C:\Reports\SharedMBXmitLizenz.csv' -NoTypeInformation -Encoding UTF8

Prüfen Sie vor dem Entfernen die Postfachgröße (Get-EXOMailboxStatistics -Identity $upn | Select-Object TotalItemSize), ob ein Archiv oder Litigation Hold aktiv ist, und blockieren Sie die Anmeldung des Kontos (Update-MgUser -UserId $upn -AccountEnabled:$false). Testen Sie das Entfernen zuerst an einem einzelnen Postfach.

# Lizenz von einer einzelnen Shared Mailbox entfernen
$upn = 'sharedbox@contoso.com'
$licenses = (Get-MgUser -UserId $upn).AssignedLicenses.SkuId
Set-MgUserLicense -UserId $upn -RemoveLicenses @($licenses) -AddLicenses @()

# Lizenzen in Massenverarbeitung aus CSV entfernen
$users = Import-Csv -Path 'C:\Reports\SharedMBXmitLizenz.csv'
foreach ($row in $users) {
  $licenses = (Get-MgUser -UserId $row.UPN).AssignedLicenses.SkuId
  Set-MgUserLicense -UserId $row.UPN -RemoveLicenses @($licenses) -AddLicenses @()
  Write-Host "Lizenz entfernt: $($row.UPN)"
}

Verifizieren: (Get-MgUser -UserId $upn -Property AssignedLicenses).AssignedLicenses.Count liefert 0; das Postfach bleibt in Outlook für die Berechtigten erreichbar. Bei Gruppenlizenzen meldet Set-MgUserLicense einen Fehler: Entfernen Sie dann das Konto aus der Lizenzgruppe.

Schritt 6: Downgrade-Kandidaten von E5 auf E3 identifizieren

Die folgende Abfrage listet alle Benutzer mit E5-Lizenz. Ob ein Downgrade möglich ist, entscheiden Sie nach Prüfung der genutzten Dienste (z. B. Defender for Endpoint P2, Power BI Pro, Entra ID P2) – das Skript liefert die Kandidatenliste.

# E5-Nutzer auflisten (Downgrade-Kandidaten-Basis)
$e5Sku = Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq 'SPE_E5' }
Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($e5Sku.SkuId))" `
  -ConsistencyLevel eventual -CountVariable e5Count -All |
  Select-Object UserPrincipalName, DisplayName |
  Export-Csv -Path 'C:\Reports\E5Nutzer.csv' -NoTypeInformation -Encoding UTF8
Write-Host "E5-Nutzer gesamt: $e5Count"

Verifizieren: Die ausgegebene Anzahl entspricht dem Wert Verbraucht für SPE_E5 aus Schritt 2.

Die Einsparung je Downgrade ergibt sich aus der Differenz Ihrer vertraglichen Preise für E5 und E3. Prüfen Sie vorher, ob Sicherheitsfunktionen aus E5 (etwa Defender for Office 365 P2 oder Entra ID P2 für PIM) im Tenant genutzt werden.

Schritt 7: Fehlende UsageLocation prüfen

Ein fehlender UsageLocation-Wert blockiert gruppenbasierte Lizenzzuweisungen vollständig. Das Konto bleibt trotz Gruppenmitgliedschaft ohne Lizenz.

# Benutzer ohne Nutzungsstandort finden
Get-MgUser -Filter 'assignedLicenses/$count ne 0' -ConsistencyLevel eventual -CountVariable anzahl -All `
  -Select UserPrincipalName,DisplayName,UsageLocation |
  Where-Object { -not $_.UsageLocation } |
  Export-Csv -Path 'C:\Reports\OhneUsageLocation.csv' -NoTypeInformation -Encoding UTF8

Verifizieren: Nach dem Setzen mit Update-MgUser -UserId <UPN> -UsageLocation 'DE' taucht das Konto beim erneuten Lauf nicht mehr auf.

Schritt 8: Spar-Rechnung aufstellen

Sobald alle CSV-Reports vorliegen, beziffern Sie das Einsparpotenzial: Anzahl freigebbarer Lizenzen je SKU multipliziert mit Ihrem vertraglichen Preis. Zählen Sie die Zeilen je Report:

Get-ChildItem C:\Reports\*.csv | ForEach-Object {
  [PSCustomObject]@{ Report = $_.Name; Zeilen = (Import-Csv $_.FullName).Count }
} | Format-Table -AutoSize
FundstelleReportEinsparung
Inaktive Konten >90 TageInaktiveLizenzierte.csvja, nach Rücksprache mit der Fachabteilung
Deaktivierte Konten mit LizenzDeaktivierteMitLizenz.csvja, nach Klärung der Postfachaufbewahrung
Shared Mailboxen mit LizenzSharedMBXmitLizenz.csvja, sofern unter 50 GB, ohne Archiv und Hold
MehrfachzuweisungenDoppellizenzen.csvnein, nur Bereinigung
E5-DowngradeE5Nutzer.csvPreisdifferenz E5/E3 je Konto

Bei Jahresverträgen reduzieren Sie die Anzahl meist nur zur Verlängerung; bereinigen Sie deshalb vorher.

Verifizieren: Die Zeilenzahlen je Report stimmen mit Ihrer Tabelle überein; nach der Bereinigung zeigt Schritt 2 entsprechend mehr freie Lizenzen.

Troubleshooting / Typische Fehler

  • „Request_UnsupportedQuery“ bei $count-Filtern: -ConsistencyLevel eventual oder -CountVariable fehlt. Beide Parameter sind nötig, wenn erweiterte OData-Filter mit $count genutzt werden.
  • SignInActivity ist immer $null: Die Eigenschaft muss per -Select angefordert werden und setzt Entra ID P1 sowie AuditLog.Read.All voraus.
  • „ProhibitedInUsageLocationViolation“ bei Gruppenlizenzen: Der Benutzer hat keinen UsageLocation-Wert gesetzt. Lösung siehe Schritt 7; die Gruppe weist die Lizenz danach automatisch zu.
  • „MutuallyExclusiveViolation“: Ein Benutzer ist Mitglied zweier Gruppen mit inkompatiblen Service-Plänen (z. B. Skype for Business Plan 1 und Plan 2). Fehlerdetails finden Sie im Entra-Überwachungsprotokoll oder in LicenseAssignmentStates.Error (Schritt 4).
  • Lizenz bleibt nach Entfernen aus der Gruppe bestehen: Es existiert zusätzlich eine direkte Zuweisung, die Microsoft nicht automatisch entfernt. Lösung: Set-MgUserLicense -RemoveLicenses @($directSkuId) -AddLicenses @() für alle betroffenen Nutzer.
  • MSOnline-Befehle (Set-MsolUserLicense) funktionieren nicht mehr: MSOnline ist eingestellt; nutzen Sie Set-MgUserLicense und Get-MgUser.
  • LicenseAssignmentStates ist leer: Die Eigenschaft wird nur mit -Property ...,LicenseAssignmentStates zurückgegeben.
  • Postfachdaten nach Lizenzentfernung verloren: Nach dem Entzug der Exchange-Lizenz bleibt ein Benutzerpostfach 30 Tage erhalten und wird dann gelöscht. Sichern Sie die Daten vorher oder setzen Sie einen Hold bzw. eine Aufbewahrungsrichtlinie, solange das Postfach noch lizenziert ist (Set-Mailbox -Identity <UPN> -LitigationHoldEnabled $true), und löschen Sie danach das Konto; das Postfach wird dann zum inaktiven Postfach.

Häufige Fragen

Kann ich einer Shared Mailbox komplett die Lizenz entziehen?

Ja, unter den Bedingungen aus Schritt 5: unter 50 GB, kein Archiv, kein Litigation Hold, Anmeldung blockiert.

Wie erkenne ich, ob eine Lizenz direkt oder per Gruppe zugewiesen wurde?

Mit dem Skript aus Schritt 4: Ist AssignedByGroup leer, ist die Lizenz direkt zugewiesen, sonst steht dort die ID der Gruppe.

Was passiert mit den Postfachdaten, wenn ich einem inaktiven Benutzer die Lizenz entziehe?

Es bleibt 30 Tage erhalten und wird danach gelöscht. Wie Sie die Daten als inaktives Postfach bewahren, steht im Troubleshooting unter „Postfachdaten nach Lizenzentfernung verloren“.

Wie groß ist das typische Einsparpotenzial?

Das hängt von Fluktuation und Offboarding ab; die Rechnung zeigt Schritt 8.

Kann ich die Preiserhöhung durch eine frühzeitige Verlängerung umgehen?

Nein, nur aufschieben: Microsoft hat die Preisanpassung zum 1. Juli 2026 umgesetzt; bestehende Verträge behalten ihre Konditionen bis zur nächsten Verlängerung. Danach gelten die neuen Preise. Bereinigen Sie die Lizenzanzahl daher vor jedem Verlängerungstermin.

Welche Berechtigungen brauche ich für den vollständigen Lizenz-Report?

Lesen: Rolle Globaler Leser mit User.Read.All, Organization.Read.All und AuditLog.Read.All. Ändern: Lizenzadministrator mit User.ReadWrite.All. Für Schritt 5 zusätzlich eine Exchange-Rolle mit Leserechten auf Empfänger.

Was ist mit dem neuen Microsoft 365 E7?

Microsoft 365 E7 („Frontier Suite“, seit Mai 2026 verfügbar) bündelt Microsoft 365 E5, Microsoft 365 Copilot, die Microsoft Entra Suite und Agent 365. Für die Bereinigung ändert sich nichts: Die Skripte erkennen E7 wie jede andere SKU in Schritt 2.

Fazit

Führen Sie die Lizenzprüfung mindestens einmal im Quartal aus, idealerweise als geplante Aufgabe mit App-Registrierung. Die CSV-Dateien dienen als Grundlage für die Vertragsverlängerung. Wer wissen möchte, wie Lizenzen in Entra ID über Gruppen zentral gesteuert werden, findet in der Anleitung zu Entra ID: Benutzer, Gruppen und Lizenzen verwalten den passenden Einstieg. Zur Absicherung der Admin-Konten siehe MFA und Conditional Access in Entra ID.

Weiterführende Anleitungen und Quellen

Quellen: Microsoft Learn – View licensed and unlicensed Microsoft 365 users with PowerShell · Microsoft Learn – Resolve group license assignment problems · Microsoft Learn – user resource (Graph v1.0) · o365reports.com – Find Unused Licenses in Microsoft 365 Using PowerShell · Microsoft Learn – About shared mailboxes