Die Verwaltung von **SharePoint Online**-Umgebungen kann eine Mammutaufgabe sein, insbesondere in großen Organisationen. Websites sprießen wie Pilze aus dem Boden, Teams gründen neue Arbeitsbereiche, und der Überblick über die tatsächliche Nutzung und Aktivität kann schnell verloren gehen. Wer ist der Besitzer einer bestimmten Site? Wann wurde sie zuletzt aktualisiert? Ist sie überhaupt noch aktiv oder verwaist? Eine manuelle Inventur ist zeitaufwendig, fehleranfällig und schnell veraltet. Doch es gibt eine elegante Lösung: Die **Automatisierung** einer dynamischen Liste aller aktiven SharePoint-Websites direkt in **MS Lists** mithilfe von **Power Automate** und der **Microsoft Graph API**.
Dieser umfassende Leitfaden zeigt Ihnen Schritt für Schritt, wie Sie eine solche Lösung implementieren können. Sie erhalten nicht nur eine Momentaufnahme Ihrer **IT-Ressourcen**, sondern schaffen ein lebendiges Inventar, das sich selbst aktualisiert und Ihnen hilft, Ihre SharePoint-Umgebung effizienter zu verwalten.
Warum eine dynamische Liste aktiver SharePoint-Websites?
Bevor wir ins Detail gehen, lassen Sie uns die Vorteile einer solchen **dynamischen Liste** beleuchten:
* **Aktueller Überblick:** Sie wissen jederzeit, welche Sites existieren, wer sie besitzt und wann sie zuletzt genutzt wurden.
* **Ressourcenoptimierung:** Identifizieren Sie inaktive oder verwaiste Sites, die gelöscht oder archiviert werden könnten, um Speicherplatz freizugeben und die Komplexität zu reduzieren.
* **Compliance und Governance:** Eine zentrale Liste erleichtert die Überprüfung von Berechtigungen, Sensitivitätsbezeichnungen und Einhaltung von Richtlinien.
* **Effiziente Verwaltung:** Statt manueller Abfragen erhalten Sie automatisch aktualisierte Daten, die als Basis für weitere administrative Aufgaben oder Berichte dienen können.
* **Bessere Entscheidungen:** Fundierte Daten über die Nutzung helfen bei strategischen Entscheidungen bezüglich SharePoint-Struktur, Schulungen und Support.
* **Transparenz:** Bietet Stakeholdern und IT-Administratoren eine transparente Sicht auf die SharePoint-Landschaft.
Kurz gesagt: Eine **automatisierte SharePoint-Inventur** ist ein Game-Changer für jede Organisation, die ihre **Microsoft 365**-Umgebung ernst nimmt.
Voraussetzungen und Werkzeuge
Um unsere **dynamische Liste** zu erstellen, benötigen Sie folgende Komponenten und Kenntnisse:
1. **Microsoft 365-Abonnement:** Mit Zugriff auf **SharePoint Online**, **MS Lists** und **Power Automate**.
2. **Berechtigungen:** Ein Benutzerkonto mit ausreichenden Rechten, um SharePoint-Websites im Tenant auszulesen (idealerweise ein Global Admin oder SharePoint Admin, oder ein Azure AD App Registration mit `Sites.Read.All` oder `SharePoint.Read.All` Anwendungsberechtigungen). Wir werden letztere, robustere Methode verwenden.
3. **Grundkenntnisse in Power Automate:** Verständnis für Trigger, Aktionen, Schleifen und Bedingungen.
4. **Grundkenntnisse der Microsoft Graph API:** Verständnis für HTTP-Anfragen, Authentifizierung und Datenstrukturen.
Schritt 1: Die MS Lists-Liste einrichten
Zuerst erstellen wir die Liste in **MS Lists**, die unsere SharePoint-Website-Daten aufnehmen wird.
1. **MS Lists öffnen:** Navigieren Sie zu Microsoft Lists (oder öffnen Sie SharePoint und erstellen Sie eine neue Liste in einer beliebigen Site).
2. **Neue Liste erstellen:** Wählen Sie „Leere Liste” und geben Sie ihr einen aussagekräftigen Namen, z.B. „Aktive SharePoint Sites”.
3. **Spalten definieren:** Fügen Sie die folgenden Spalten hinzu (der Typ ist in Klammern angegeben):
* **Titel** (Text – wird für den Seitennamen verwendet)
* **WebUrl** (Hyperlink – die URL der SharePoint-Site)
* **Beschreibung** (Mehrzeiliger Text)
* **ErstelltAm** (Datum und Uhrzeit)
* **ZuletztGeändertAm** (Datum und Uhrzeit)
* **Besitzer** (Person oder Gruppe – optional, kann aus der Graph API geholt werden, ist aber komplexer, da der Besitzer meist eine Gruppe ist, keine Einzelperson direkt an der Site)
* **SiteId** (Text – die eindeutige ID der Site aus der Graph API, sehr wichtig für Updates)
* **LastChecked** (Datum und Uhrzeit – wann die Site zuletzt vom Flow überprüft wurde)
* **IsActive** (Ja/Nein – um Sites zu markieren, die als aktiv gelten)
* **SiteCollectionUrl** (Hyperlink – die URL der Site-Sammlung, nützlich für die Struktur)
Diese Spalten bilden die Grundlage für unser Inventar und ermöglichen es uns, umfassende Informationen zu speichern und später zu filtern.
Schritt 2: Azure AD App-Registrierung für Graph API-Zugriff
Um die **Microsoft Graph API** im Tenant abfragen zu können, benötigen wir eine **Azure AD App-Registrierung** mit den entsprechenden Berechtigungen. Dies ist der sicherste und robusteste Weg, um auf tenantweite Daten zuzugreifen, ohne die Anmeldeinformationen eines spezifischen Benutzers zu verwenden.
1. **Azure-Portal öffnen:** Melden Sie sich unter portal.azure.com an.
2. **App-Registrierungen:** Suchen Sie nach „App-Registrierungen” und klicken Sie auf „Neue Registrierung”.
3. **Registrierungsdetails:**
* **Name:** Geben Sie einen Namen wie „SharePointSiteInventoryApp” ein.
* **Unterstützte Kontotypen:** Wählen Sie „Nur Konten in diesem Organisationsverzeichnis (Standardverzeichnis – Einzelner Mandant)”.
* Klicken Sie auf „Registrieren”.
4. **Clientgeheimnis erstellen:**
* Gehen Sie zu „Zertifikate und Geheimnisse” und klicken Sie auf „Neues Clientgeheimnis”.
* Geben Sie eine Beschreibung (z.B. „Power Automate Flow Secret”) und eine Ablaufzeit ein (z.B. 12 Monate).
* **WICHTIG:** Kopieren Sie den **Wert** des Geheimnisses SOFORT, nachdem es erstellt wurde. Er wird nach dem Verlassen dieser Seite nicht mehr angezeigt und wird später im Power Automate Flow benötigt.
5. **API-Berechtigungen hinzufügen:**
* Gehen Sie zu „API-Berechtigungen” und klicken Sie auf „Berechtigung hinzufügen”.
* Wählen Sie „Microsoft Graph”.
* Wählen Sie „Anwendungsberechtigungen” (nicht delegierte Berechtigungen, da der Flow ohne Benutzerinteraktion ausgeführt wird).
* Suchen Sie nach `Sites.Read.All` und `User.Read.All` (für eventuelle Besitzerinformationen, obwohl `Sites.Read.All` für die Website-Details relevanter ist). **`Sites.Read.All` ist für das Auslesen aller SharePoint-Websites entscheidend.**
* Klicken Sie auf „Berechtigungen hinzufügen”.
* **WICHTIG:** Klicken Sie auf „Administratorzustimmung für [Ihr Tenant]” erteilen, um die Anwendungsberechtigungen zu aktivieren. Ohne dies funktioniert der Flow nicht.
6. **Anwendungs-ID und Mandanten-ID:** Notieren Sie sich die „Anwendungs-(Client)-ID” und die „Verzeichnis-(Mandanten)-ID” von der Übersichtsseite Ihrer App-Registrierung. Diese benötigen wir ebenfalls für Power Automate.
Schritt 3: Den Power Automate Flow erstellen
Jetzt kommt der Kern der **Automatisierung**: Ein Flow, der regelmäßig ausgeführt wird, um die SharePoint-Websites abzurufen und unsere **MS Lists-Liste** zu aktualisieren.
1. **Neuen Flow erstellen:**
* Navigieren Sie zu Power Automate (flow.microsoft.com).
* Wählen Sie „Neuen Flow erstellen” > „Geplanter Cloud-Flow”.
* Geben Sie einen Namen ein (z.B. „SharePoint Site Inventory Update”), stellen Sie die Startzeit ein und wählen Sie die Wiederholungsfrequenz (z.B. alle 24 Stunden für eine tägliche Aktualisierung). Klicken Sie auf „Erstellen”.
2. **Trigger: Wiederholung (Recurrence)**
* Dieser Trigger ist bereits konfiguriert, passen Sie die Frequenz bei Bedarf an. Eine tägliche oder wöchentliche Ausführung ist für die meisten Zwecke ausreichend.
3. **Aktion: Azure AD Access Token abrufen**
* Verwenden Sie die Aktion „HTTP” (Premium-Konnektor, aber für die Graph API unerlässlich).
* **Methode:** `POST`
* **URI:** `https://login.microsoftonline.yourtenantid/oauth2/v2.0/token` (Ersetzen Sie `yourtenantid` durch Ihre Verzeichnis-(Mandanten)-ID).
* **Header:** `Content-Type: application/x-www-form-urlencoded`
* **Body:**
„`
client_id=YOUR_CLIENT_ID
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=YOUR_CLIENT_SECRET_VALUE
&grant_type=client_credentials
„`
Ersetzen Sie `YOUR_CLIENT_ID` und `YOUR_CLIENT_SECRET_VALUE` durch die Werte aus Ihrer App-Registrierung.
* Nennen Sie diese Aktion um in „Access Token abrufen”.
4. **Aktion: SharePoint-Websites über Graph API abrufen (mit Pagination)**
Die Graph API gibt Ergebnisse oft seitenweise zurück (`@odata.nextLink`). Wir müssen dies in einer Schleife handhaben.
* **Variable initialisieren:** Fügen Sie eine Aktion „Variable initialisieren” hinzu.
* **Name:** `NextLink`
* **Typ:** `String`
* **Wert:** `https://graph.microsoft.com/v1.0/sites?select=id,name,webUrl,description,createdDateTime,lastModifiedDateTime,siteCollection&top=999`
(Der Parameter `top=999` maximiert die Anzahl der Sites pro Abfrage, kann aber je nach Tenant-Größe und Graph API-Limits variieren. Die `select`-Parameter sind wichtig, um nur die benötigten Daten zu holen.)
* **Schleife: Do until**
* Fügen Sie eine Aktion „Do until” hinzu.
* **Bedingung:** `NextLink` ist gleich (is equal to) `null`.
* **Innerhalb der „Do until”-Schleife:**
* **Aktion: HTTP-Anfrage an Graph API**
* **Methode:** `GET`
* **URI:** `variables(‘NextLink’)`
* **Header:** `Authorization: Bearer @{body(‘Access_Token_abrufen’)?[‘access_token’]}`
* Nennen Sie diese Aktion um in „Graph API Sites abrufen”.
* **Aktion: JSON analysieren (Parse JSON)**
* **Inhalt:** `body(‘Graph_API_Sites_abrufen’)`
* **Schema:** Generieren Sie das Schema aus einer Beispielausgabe der Graph API (führen Sie den Flow einmal manuell aus und kopieren Sie die Ausgabe der Graph API-Aktion in den Schema-Generator). Ein vereinfachtes Schema sieht etwa so aus:
„`json
{
„type”: „object”,
„properties”: {
„@@odata.context”: { „type”: „string” },
„value”: {
„type”: „array”,
„items”: {
„type”: „object”,
„properties”: {
„id”: { „type”: „string” },
„name”: { „type”: „string” },
„webUrl”: { „type”: „string” },
„description”: { „type”: [„string”, „null”] },
„createdDateTime”: { „type”: „string” },
„lastModifiedDateTime”: { „type”: „string” },
„siteCollection”: {
„type”: „object”,
„properties”: {
„hostname”: { „type”: „string” },
„id”: { „type”: „string” }
}
}
},
„required”: [„id”, „name”, „webUrl”, „createdDateTime”, „lastModifiedDateTime”]
}
},
„@@odata.nextLink”: { „type”: [„string”, „null”] }
}
}
„`
* Nennen Sie diese Aktion um in „Sites JSON analysieren”.
* **Variable festlegen:** Fügen Sie eine Aktion „Variable festlegen” hinzu, um den `NextLink` für die nächste Iteration zu aktualisieren.
* **Name:** `NextLink`
* **Wert:** `@{body(‘Sites_JSON_analysieren’)?[‘@odata.nextLink’]}`
* **Schleife: Für jedes Element anwenden (Apply to each)**
* **Wählen Sie eine Ausgabe aus den vorherigen Schritten:** `body(‘Sites_JSON_analysieren’)?[‘value’]` (Dies sind die einzelnen Site-Objekte).
* **Innerhalb der „Für jedes Element anwenden”-Schleife:**
* **Bedingung (Optional: Filter für „aktive” Sites):** Fügen Sie eine „Bedingung” hinzu, um nur Sites zu verarbeiten, die als „aktiv” gelten. Eine Site könnte als aktiv gelten, wenn `lastModifiedDateTime` innerhalb der letzten X Monate liegt.
* Beispiel: `@lessOrEquals(item()?[‘lastModifiedDateTime’], addDays(utcNow(), -365))` würde Sites ausschließen, die seit über einem Jahr nicht geändert wurden. Passen Sie dies an Ihre Definition von „aktiv” an. Wenn Sie alle Sites listen wollen, können Sie diese Bedingung auch weglassen.
* **Wenn ja (Site ist aktiv oder Sie verarbeiten alle Sites):**
* **Aktion: Elemente abrufen (Get items) aus MS Lists**
* **Websiteadresse:** Wählen Sie die SharePoint-Site, auf der Ihre MS Lists-Liste liegt.
* **Listenname:** Wählen Sie „Aktive SharePoint Sites”.
* **Filterabfrage:** `SiteId eq ‘@{items(‘Für_jedes_Element_anwenden’)?[‘id’]}’` (Verwenden Sie die SiteId, um zu prüfen, ob die Site bereits in Ihrer Liste ist).
* **Bedingung: Wenn Elemente gefunden wurden (Update) oder nicht (Erstellen)**
* **Bedingung:** `@empty(body(‘Elemente_abrufen’)?[‘value’])` ist gleich `false` (d.h. die Site existiert bereits in der Liste).
* **Wenn „Ja” (Site existiert):**
* **Aktion: Element aktualisieren (Update item)**
* **Websiteadresse/Listenname:** Ihre MS Lists-Liste.
* **ID:** `body(‘Elemente_abrufen’)?[‘value’][0]?[‘ID’]` (Die ID des gefundenen Elements).
* **Titel:** `items(‘Für_jedes_Element_anwenden’)?[‘name’]`
* **WebUrl:** `items(‘Für_jedes_Element_anwenden’)?[‘webUrl’]`
* **Beschreibung:** `items(‘Für_jedes_Element_anwenden’)?[‘description’]`
* **ErstelltAm:** `items(‘Für_jedes_Element_anwenden’)?[‘createdDateTime’]`
* **ZuletztGeändertAm:** `items(‘Für_jedes_Element_anwenden’)?[‘lastModifiedDateTime’]`
* **SiteId:** `items(‘Für_jedes_Element_anwenden’)?[‘id’]`
* **LastChecked:** `utcNow()`
* **IsActive:** `true`
* **SiteCollectionUrl:** `items(‘Für_jedes_Element_anwenden’)?[‘siteCollection’]?[‘hostname’]` (oder `items(‘Für_jedes_Element_anwenden’)?[‘siteCollection’]?[‘webUrl’]` falls verfügbar und aussagekräftiger)
* **Wenn „Nein” (Site existiert nicht):**
* **Aktion: Element erstellen (Create item)**
* **Websiteadresse/Listenname:** Ihre MS Lists-Liste.
* Füllen Sie die Spalten wie beim „Element aktualisieren” aus.
* Speichern Sie Ihren Flow.
Fortgeschrittene Überlegungen und Best Practices
* **Fehlerbehandlung:** Implementieren Sie „Try-Catch”-Blöcke oder „Nach”-Konfigurationen für Aktionen, die fehlschlagen könnten (z.B. Graph API-Aufrufe), um den Flow robust zu machen. Senden Sie Benachrichtigungen bei Fehlern.
* **Performance und Skalierung:** Für sehr große Tenants (>10.000 Sites) kann der Graph API-Aufruf und die anschließende Verarbeitung lange dauern. Optimieren Sie die Filter und `select`-Anweisungen. Überlegen Sie, ob Sie den Flow in kleinere Teile aufteilen oder die Häufigkeit reduzieren müssen.
* **Behandlung gelöschter Sites:** Die aktuelle Logik erkennt nur neue und aktualisiert bestehende Sites. Gelöschte Sites bleiben in Ihrer MS Lists-Liste, es sei denn, Sie implementieren eine zusätzliche Logik:
1. Fügen Sie eine Spalte „IsPresentInGraph” (Ja/Nein) in Ihre Liste ein.
2. Setzen Sie vor der „Für jedes Element anwenden”-Schleife alle „IsPresentInGraph” auf „Nein” (mit einem separaten „Update items” Batch-Update).
3. Setzen Sie in der Schleife, wenn eine Site gefunden und aktualisiert/erstellt wird, „IsPresentInGraph” auf „Ja”.
4. Nach der Hauptschleife führen Sie eine Abfrage für alle Elemente in Ihrer Liste durch, bei denen „IsPresentInGraph” noch „Nein” ist. Diese Sites wurden nicht von der Graph API zurückgegeben und sind wahrscheinlich gelöscht oder nicht mehr zugänglich. Sie können diese dann löschen oder als „Inaktiv” markieren.
* **Detailliertere Site-Informationen:** Die Graph API bietet noch viele weitere Informationen über Sites, z.B. Speichernutzung, Sensitivitätsbezeichnungen, Hub-Site-Assoziationen usw. Sie können weitere `select`-Parameter in Ihrer Graph API-Abfrage hinzufügen und entsprechende Spalten in Ihrer MS Lists-Liste erstellen.
* **Visualisierung und Berichterstattung:** Verbinden Sie Ihre **MS Lists-Liste** mit **Power BI**, um ansprechende Dashboards und Berichte über Ihre SharePoint-Landschaft zu erstellen. Dies ermöglicht eine tiefere Analyse und schnellere Entscheidungsfindung.
Fazit
Die **Automatisierung** Ihrer **SharePoint Online**-Inventur mit **MS Lists** und **Power Automate**, unterstützt durch die **Microsoft Graph API**, ist eine Investition, die sich schnell auszahlt. Sie verwandeln eine statische, schnell veraltende Momentaufnahme in eine **dynamische Liste**, die Ihnen stets einen aktuellen und präzisen Überblick über Ihre **aktiven SharePoint Websites** bietet. Dies verbessert nicht nur die **Tenant-Verwaltung** und die **Governance**, sondern optimiert auch die Nutzung Ihrer **Microsoft 365**-Ressourcen. Beginnen Sie noch heute mit der Implementierung und übernehmen Sie die Kontrolle über Ihre SharePoint-Umgebung!