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

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

Microsoft hebt die M365-Preise ab Juli 2026 um bis zu 17 % an – der ideale Zeitpunkt, um mit PowerShell und der Microsoft Graph API inaktive Konten, Doppelzuweisungen und lizenzierte Shared Mailboxen aufzuspüren. Diese Anleitung liefert zwölf einsatzbereite Skripte und eine Spar-Rechnung.

Holografisches M365-Admin-Dashboard mit PowerShell-Terminal und Lizenzkosten-Diagrammen

Microsoft 365 gehört für die meisten Unternehmen zu den größten monatlichen IT-Ausgaben – und trotzdem schlummern in nahezu jedem Tenant ungenutzte Lizenzen still vor sich hin. Erfahrungswerte aus der Praxis zeigen, dass 10–30 % der gebuchten Lizenzen in KMU und Mittelstand redundant oder gar nicht mehr in Benutzung sind. Ab dem 1. Juli 2026 steigen die M365-Preise je nach SKU um 5–17 %, was eine gezielte Bereinigung besonders lohnend macht. Diese Anleitung zeigt dir, wie du mit dem Microsoft Graph PowerShell SDK in unter 90 Minuten einen vollständigen Lizenz-Report erstellst, Einsparpotenziale bezifferst und Lizenzen sauber entfernst.

Voraussetzungen

  • Microsoft 365-Tenant; Rolle: Global Administrator, Lizenzadministrator oder Global Reader (letzterer nur für den Lesezugriff)
  • PowerShell 7.x (empfohlen) oder Windows PowerShell 5.1
  • Microsoft Graph PowerShell SDK: Install-Module Microsoft.Graph -Scope CurrentUser
  • Microsoft Graph Beta SDK (für LicenseAssignmentStates): Install-Module Microsoft.Graph.Beta -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-Berechtigungen User.Read.All und Organization.Read.All

Schritt 1: Verbindung herstellen und Module prüfen

Stelle zunächst sicher, dass die benötigten Module in aktueller Version installiert sind. Die alten MSOnline- und AzureAD-Module sind seit dem 30. März 2024 abgekündigt und erhalten seit März 2025 nur noch eingeschränkten Support – verwende sie nicht mehr.

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

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

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

Schritt 2: Gebuchte SKUs und freie Lizenzen überblicken

Der erste Blick gilt den gebuchten Lizenz-SKUs. Die Differenz zwischen PrepaidUnits.Enabled (bezahlte Plätze) und ConsumedUnits (zugewiesene Plätze) ergibt die sofort einsparbaren, ungenutzten Lizenzen.

# 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:

SkuPartNumberProduktPreis ab Juli 2026 (USD/Nutzer/Monat)
SPE_E3Microsoft 365 E339 USD (+8 %)
SPE_E5Microsoft 365 E560 USD (+5 %)
O365_BUSINESS_PREMIUMM365 Business Premium
ENTERPRISEPREMIUMOffice 365 E3
BUSINESSBASICM365 Business Basic7 USD (+16 %)
O365_BUSINESSM365 Apps for Business14 USD (+17 %)

Schritt 3: Inaktive Benutzer mit Lizenzen finden

Als inaktiv gilt ein Konto, das sich seit mehr als 90 Tagen nicht angemeldet hat. Wichtig: Die Eigenschaft SignInActivity muss explizit per -Select angefordert werden, da sie sonst nicht zurückgegeben wird. Außerdem sind -ConsistencyLevel eventual und -CountVariable Pflicht bei erweiterten $count-Filtern.

# Inaktive Benutzer (>90 Tage keine Anmeldung) mit Lizenzen
$cutoff = (Get-Date).AddDays(-90)
Get-MgUser -Filter 'assignedLicenses/$count ne 0' `
  -ConsistencyLevel eventual -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 -All `
  -Select UserPrincipalName,DisplayName,AccountEnabled,AssignedLicenses |
  Export-Csv -Path 'C:\Reports\DeaktivierteMitLizenz.csv' -NoTypeInformation -Encoding UTF8

Schritt 4: Direkte vs. gruppenbasierte Lizenzzuweisungen analysieren

Seit September 2024 lässt sich die Lizenzzuweisung über das Entra-ID- und Azure-Portal nicht mehr per UI verwalten. Über die Graph-Eigenschaft LicenseAssignmentStates erkennst du genau, ob eine Lizenz direkt oder über eine Gruppe vergeben wurde. Diese Eigenschaft ist nur über den Beta-Endpunkt (Get-MgBetaUser) verfügbar.

# Direkte vs. gruppenbasierte Lizenzzuweisung prüfen
Get-MgBetaUser -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

Auf Basis dieser CSV erkennst du anschließend Doppelzuweisungen: ein Nutzer hat dieselbe SKU sowohl direkt als auch über eine Gruppe zugewiesen bekommen. Microsoft entfernt diese Duplikate nicht automatisch – beide Einträge verbrauchen je einen Lizenz-Slot.

# Doppelzuweisungen (Direkt + Gruppe für gleiche SKU) erkennen
$doppelt = Get-MgBetaUser -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

Schritt 5: Lizenzierte Shared Mailboxen aufspüren

Shared Mailboxen benötigen bis zu einer Postfachgröße von 50 GB keine Lizenz. Viele Tenants tragen trotzdem vollwertige Lizenzen in diese Konten ein – oft ein Relikt aus der Vergangenheit. Für diesen Schritt sind beide Verbindungen nötig: 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

Lizenz entfernen: Stelle vor dem Entfernen sicher, dass das Postfach kleiner als 50 GB ist und der Sign-In des Kontos deaktiviert wird (Update-MgUser -UserId $upn -AccountEnabled $false). Andernfalls markiert Microsoft das Konto ab 2025 als „non-compliant".

# 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)"
}

Schritt 6: Downgrade-Kandidaten von E5 auf E3 identifizieren

Nicht jeder E5-Nutzer braucht E5-Features. Die folgende Abfrage listet alle Nutzer mit einer aktiven E5-Lizenz auf. Die Entscheidung über einen Downgrade erfordert eine manuelle Prüfung der genutzten Services (z. B. Defender for Endpoint P2, Power BI Pro, Azure AD 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"

Mögliches Einsparpotenzial beim Downgrade: E5 kostet ab Juli 2026 60 USD, E3 nur noch 39 USD – das sind 21 USD pro Nutzer und Monat. Bei zehn Downgrade-Kandidaten ergibt das 2.520 USD im Jahr.

Schritt 7: Fehlende UsageLocation prüfen

Ein fehlender UsageLocation-Wert blockiert gruppenbasierte Lizenzzuweisungen vollständig. Das Konto bleibt ohne Lizenz, obwohl es Mitglied einer lizenzierten Gruppe ist – ohne sichtbaren Fehler im Admin Center. Diese Abfrage deckt betroffene Konten auf.

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

Schritt 8: Spar-Rechnung aufstellen

Sobald alle CSV-Reports vorliegen, lässt sich das Einsparpotenzial konkret beziffern. Das folgende Beispiel bezieht sich auf einen Tenant mit 100 E3-Lizenzen zum neuen Preis (39 USD ab Juli 2026):

FundstelleTypische QuoteBeispiel (100 E3)Ersparnis/Jahr (USD)
Inaktive Konten >90 Tage5–15 %10 Lizenzen4.680 USD
Deaktivierte Konten mit Lizenz2–5 %3 Lizenzen1.404 USD
Shared Mailboxen mit Lizenz2–8 %5 Lizenzen2.340 USD
Doppelzuweisungen (direkt + Gruppe)1–5 %3 Lizenzen1.404 USD
Gesamt (konservativ 10 %)10 %21 Lizenzen9.828 USD

Für EUR-Kunden mit Jahresvertrag lohnt sich zusätzlich ein Blick auf den Vertragszeitpunkt: Bestandsverträge behalten den alten Preis bis zur nächsten Verlängerung. Eine Verlängerung vor dem 1. Juli 2026 sichert die alten USD-Preise; im Zeitfenster Februar–Juni 2026 profitieren EUR-Kunden durch die aktuelle FX-Korrektur noch einmal zusätzlich.

Troubleshooting / Typische Fehler

  • „Request_UnsupportedQuery" bei $count-Filtern: Du hast entweder -ConsistencyLevel eventual oder -CountVariable vergessen. Beide Parameter sind gleichzeitig Pflicht, wenn erweiterte OData-Filter mit $count genutzt werden.
  • SignInActivity ist immer $null: Die Eigenschaft wird nur zurückgegeben, wenn sie explizit per -Select ...,SignInActivity angefordert wird. Ohne den -Select-Parameter bleibt das Feld leer, auch wenn Anmeldeaktivität vorhanden ist.
  • „ProhibitedInUsageLocationViolation" bei Gruppenlizenzen: Der Benutzer hat keinen UsageLocation-Wert gesetzt. Fix: Update-MgUser -UserId <UPN> -UsageLocation 'DE' (ISO 3166-1 Alpha-2-Code). Die Lizenz wird danach beim nächsten Sync-Zyklus automatisch zugewiesen.
  • „MutuallyExclusiveViolation": Ein Benutzer ist Mitglied zweier Gruppen mit inkompatiblen Service-Plänen (z. B. Skype for Business Plan 1 und Plan 2). Die Zuweisung schlägt still fehl. Fehlerdetails findest du im Entra-Audit-Log oder per LicenseAssignmentStates.Error über Get-MgBetaUser.
  • Doppellizenzen bleiben nach Gruppenbasierung bestehen: Wenn eine direkte Zuweisung bestand, bevor eine gruppenbasierte hinzukam, koexistieren beide. Microsoft entfernt die direkte Zuweisung nicht automatisch. Lösung: Set-MgUserLicense -RemoveLicenses @($directSkuId) -AddLicenses @() für alle betroffenen Nutzer.
  • MSOnline-Befehle (Set-MsolUserLicense) funktionieren nicht mehr: Diese Module sind seit März 2024 abgekündigt. Migriere alle Skripte auf Set-MgUserLicense bzw. Get-MgUser aus dem Microsoft.Graph-Modul.
  • LicenseAssignmentStates nicht verfügbar bei Get-MgUser: Diese Eigenschaft ist nur über den Beta-Endpunkt abrufbar. Verwende Get-MgBetaUser mit installiertem Microsoft.Graph.Beta-Modul. Beta-APIs sollten in Produktion sorgfältig getestet werden.
  • Postfachdaten nach Lizenzentfernung verloren: Wenn ein Benutzer ohne aktiven Litigation Hold oder Aufbewahrungsrichtlinie gelöscht wird, ist das Postfach nach 30 Tagen endgültig weg. Setze Hold vor dem Entfernen der Lizenz: Set-Mailbox -LitigationHoldEnabled $true.

Häufige Fragen

Kann ich einer Shared Mailbox komplett die Lizenz entziehen?

Ja, sofern das Postfach kleiner als 50 GB ist und der Sign-In des Kontos deaktiviert wird. Führe vor der Lizenzentfernung Update-MgUser -UserId <UPN> -AccountEnabled $false aus. Ab 50 GB Postfachgröße ist Exchange Online Plan 2 erforderlich; außerdem braucht jede Mailbox mit aktivem Microsoft Defender for Office 365 P2-Schutz eine entsprechende MDO-Lizenz.

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

Über die Graph-Eigenschaft LicenseAssignmentStates, die nur via Get-MgBetaUser abrufbar ist: Ist AssignedByGroup leer, handelt es sich um eine Direktzuweisung; enthält das Feld eine GUID, ist es eine gruppenbasierte Zuweisung. Die CSV-Datei aus Schritt 4 listet alle Kombinationen übersichtlich auf.

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

Das Postfach wird in den Status einer Inactive Mailbox überführt, wenn zuvor ein Litigation Hold oder eine M365-Aufbewahrungsrichtlinie aktiv war. Die Daten bleiben dann für eDiscovery erhalten, ohne dass eine Benutzerlizenz nötig ist. Ohne Hold sind die Daten nach 30 Tagen endgültig gelöscht. Prüfe daher immer den Hold-Status, bevor du eine Lizenz entfernst oder ein Konto löschst.

Wie groß ist das typische Einsparpotenzial?

Erfahrungswerte nennen 10–30 % redundante oder ungenutzte Lizenzen. Bei 100 E3-Lizenzen zum neuen Preis von 39 USD entsprechen bereits 10 % Ersparnis knapp 4.700 USD pro Jahr. In größeren Tenants mit einem Mix aus E3, E5 und Business-Lizenzen übersteigt das Potenzial häufig fünfstellige Jahresbeträge.

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

Ja. Bestehende Jahresverträge behalten den alten Preis bis zur nächsten Erneuerung. Eine Verlängerung vor dem 1. Juli 2026 sichert die alten USD-Listenpreise für ein weiteres Jahr. EUR-Kunden profitieren im Zeitfenster Februar–Juni 2026 zusätzlich von einer günstigen Wechselkurskorrektur (ca. –7,4 %).

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

Für einen reinen Lesezugriff reicht die Rolle Global Reader sowie die Graph-Berechtigungen User.Read.All und Organization.Read.All. Für das Entfernen von Lizenzen benötigst du Lizenzadministrator und zusätzlich User.ReadWrite.All. Für Shared-Mailbox-Abfragen via Exchange Online ist außerdem die Rolle Exchange Administrator oder View-Only Recipients nötig.

Was ist mit dem neuen Microsoft 365 E7?

Microsoft hat E7 als neues Premium-Bundle angekündigt (99 USD/Nutzer/Monat, ab 2026), das M365 E5, Copilot, Agent 365 und die Entra Suite inkl. Teams bündelt. Für die meisten KMU-Tenants ist das kein Downgrade-Ziel, aber ein Argument mehr, den aktuellen Lizenzmix kritisch zu prüfen, bevor Neuverhandlungen anstehen.

Fazit

Eine systematische Lizenzbereinigung per PowerShell ist kein einmaliges Projekt, sondern sollte mindestens einmal im Quartal – idealerweise als geplanter Task – ausgeführt werden. Die acht Schritte in dieser Anleitung decken die häufigsten Einsparpotenziale ab: inaktive Konten, deaktivierte Konten mit Lizenz, Doppelzuweisungen und lizenzierte Shared Mailboxen. Die Ergebnisse als CSV-Dateien eignen sich direkt als Basis für die jährliche Lizenzprüfung oder als Diskussionsgrundlage im nächsten Budgetgespräch. Mit der M365-Preiserhöhung ab Juli 2026 ist die Wirtschaftlichkeit einer solchen Bereinigung so hoch wie nie. Wer außerdem 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. Für die abgesicherte Ausführung der Skripte in einer produktiven Umgebung empfiehlt sich außerdem ein Blick auf 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 Licensing News – 2026 M365 Packaging and Pricing Updates · o365reports.com – Find Unused Licenses in Microsoft 365 Using PowerShell · Microsoft Learn – About shared mailboxes