Intune-Kurs · Teil 51 von 90 · Block G: Scripting & Automatisierung
Was du in dieser Sektion lernst
- Intune-Geräte, Entra-Geräteobjekte und Benutzer sauber auseinanderhalten
- Mit $select und $filter nur die Daten holen, die du brauchst
- Erweiterte Abfragen mit ConsistencyLevel: eventual und $count
- Einen Gerätebericht mit Benutzerdaten als CSV bauen und Anfragen bündeln
ca. 11 Min. Lesezeit · Alle Sektionen im Überblick
In Sektion 50 hast du dich bei Microsoft Graph angemeldet und deine erste Geräteliste gezogen. Jetzt wird es konkret: Welche Geräte sind nicht konform? Welche haben sich seit Wochen nicht gemeldet? Wem gehören sie, in welcher Abteilung sitzt die Person, und ist ihr Konto überhaupt noch aktiv?
Genau diese Fragen landen im Alltag ständig bei dir, meist kurz vor einem Audit oder wenn die Geschäftsführung eine Liste will. Im Portal klickst du dich dafür durch mehrere Ansichten. Mit Graph beantwortest du sie mit ein paar gezielten Abfragen und hast am Ende eine CSV-Datei, die du einfach wieder erzeugen kannst.
Grundlagen: Drei Arten von Objekten
Bevor du abfragst, musst du wissen, wo die Daten liegen. Für Geräte gibt es in Graph zwei verschiedene Sammlungen, und das sorgt am Anfang oft für Verwirrung. Den Hintergrund kennst du aus Sektion 02.
- Intune-Geräte unter
/deviceManagement/managedDevices: alles, was Intune verwaltet, mit Compliance-Status, letzter Synchronisierung, Seriennummer und primärem Benutzer. Laut Microsoft Learn brauchst du dafürDeviceManagementManagedDevices.Read.All. - Entra-Geräteobjekte unter
/devices: die Identität des Geräts im Verzeichnis, mit Vertrauenstyp und ungefährer letzter Anmeldung. Hier reicht laut Microsoft LearnDevice.Read.All. - Benutzer unter
/users: Name, Abteilung, Kontostatus. Für Felder wiedepartmentbrauchst duUser.Read.All,User.ReadBasic.Allliefert nur Basisdaten.
Die Brücke zwischen beiden Gerätewelten ist die Eigenschaft azureADDeviceId am Intune-Gerät. Sie entspricht laut Ressourcenbeschreibung der deviceId des Entra-Objekts, nicht dessen id. Wer hier die falsche ID nimmt, findet nichts und wundert sich.
Gezielt abfragen: $select und $filter
$select: nur die Felder, die du brauchst
Ein einzelnes Intune-Gerät liefert ohne Einschränkung weit über 50 Eigenschaften. Mit $select holst du nur das, was du wirklich auswertest. Das macht die Antwort kleiner, das Skript schneller und die Ausgabe lesbarer. Die Übersicht zu Abfrageparametern erklärt alle Optionen.
$filter: Was Intune-Geräte unterstützen
Nicht jede Eigenschaft lässt sich filtern. Die Ressourcenbeschreibung von managedDevice nennt es pro Feld. Zwei Beispiele, die du ständig brauchst:
complianceStateunterstütztequndor, zum BeispielcomplianceState eq 'noncompliant'.lastSyncDateTimeundenrolledDateTimeunterstützenltundgt, zum BeispiellastSyncDateTime lt 2026-10-01T00:00:00Z.
Für Felder ohne dokumentierte Filterunterstützung holst du die Daten mit $select und filterst lokal mit Where-Object. Das ist bei ein paar tausend Geräten kein Problem und zuverlässiger, als auf einen Filter zu hoffen, der still ignoriert wird.
Praxis 1: Anmelden und eine Hilfsfunktion für alle Seiten
Alle Beispiele in dieser Sektion lesen nur. Du meldest dich deshalb ausschließlich mit Read-Berechtigungen an. Die Funktion Get-GraphAll folgt dem @odata.nextLink, bis alle Seiten da sind. Das Prinzip kennst du aus Sektion 50, laut Microsoft Learn solltest du den Link immer vollständig übernehmen und nicht selbst zusammenbauen.
Neu ist der Parameter -Headers. Den brauchst du gleich für erweiterte Abfragen auf Benutzer und Entra-Geräte.
Praxis 2: Nicht konforme und veraltete Intune-Geräte
Das folgende Skript beantwortet zwei typische Fragen: Welche Geräte sind gerade nicht konform, und welche haben sich seit 30 Tagen nicht mehr synchronisiert?
- [uri]::EscapeDataString() kodiert Leerzeichen und Hochkommas im Filter. So gibt es keine Überraschungen mit Sonderzeichen in der URL.
- Das Backtick-Zeichen vor
?und$verhindert, dass PowerShell$filteroder$selectals eigene Variable auswertet. - Datumswerte gibst du in UTC im ISO-8601-Format an, ohne Anführungszeichen.
- @() um den Aufruf sorgt dafür, dass
.Countauch bei genau einem Treffer stimmt.
Die Zahlen aus diesem Skript passen gut zu den Compliance-Berichten aus Sektion 30. Der Unterschied: Hier kannst du sie jeden Morgen automatisch erzeugen und weiterverarbeiten.
Praxis 3: Benutzer und Entra-Geräte mit erweiterten Abfragen
Bei Verzeichnisobjekten wie Benutzern und Entra-Geräten funktionieren manche Filter nur als erweiterte Abfrage. Dazu gehören laut Microsoft Learn unter anderem endsWith, ne, not sowie $filter und $orderby in derselben Anfrage. Dafür setzt du den Header ConsistencyLevel: eventual und hängst $count=true an.
- endsWith funktioniert laut Dokumentation nur bei
mail,otherMails,userPrincipalNameundproxyAddresses. - $top=999 ist die maximale Seitengröße bei Benutzern, Standard sind 100. Fragst du
signInActivityab, sind es höchstens 500. Dafür brauchst du laut Microsoft Learn zusätzlichAuditLog.Read.Allund eine Lizenz für Entra ID P1 oder P2. - approximateLastSignInDateTime ist, wie der Name sagt, ungefähr. Für eine Bereinigungsliste reicht das, als exakter Zeitstempel taugt es nicht.
- eventual bedeutet: Der Index kann wenige Momente hinter dem aktuellen Stand liegen. Ein gerade angelegtes Konto taucht eventuell erst kurz später auf.
Vorsicht beim Aufräumen: Ein Entra-Gerät ohne Anmeldung seit 90 Tagen ist ein Kandidat zum Prüfen, kein automatischer Löschfall. Für Gruppen, die du darauf aufbaust, sind dynamische Regeln aus Sektion 07 oft die bessere Wahl.
Praxis 4: Gerätebericht mit Benutzerdaten als CSV
Jetzt verbindest du beide Welten. Das Skript lädt alle Intune-Geräte und alle Benutzer jeweils einmal und verknüpft sie lokal über den Benutzerprinzipalnamen. Das ist deutlich schneller, als für jedes Gerät einzeln nach dem Benutzer zu fragen.
- Hashtable statt Schleife in der Schleife: Das Nachschlagen per UPN dauert konstant kurz, egal wie viele Benutzer du hast. PowerShell-Hashtables vergleichen Schlüssel standardmäßig ohne Groß- und Kleinschreibung, unterschiedlich geschriebene UPNs passen also trotzdem zusammen.
- Geräte ohne Benutzer wie Kiosk-Systeme oder mit Self-Deploying bereitgestellte Geräte bekommen einen eigenen Eintrag statt eines Fehlers.
- Semikolon und UTF-8:
-Delimiter';'sorgt dafür, dass ein deutsches Excel die Spalten direkt trennt,-Encoding utf8hält die Umlaute intakt. - Der Abschluss zeigt Geräte, deren Benutzerkonto deaktiviert ist. Das sind oft Rechner ausgeschiedener Kollegen, die noch eingesammelt werden müssen.
Praxis 5: Viele Einzelabfragen bündeln mit $batch
Manchmal brauchst du nur ein paar bestimmte Benutzer, zum Beispiel aus einer Ticketliste. Statt für jeden eine eigene Anfrage zu schicken, bündelst du laut Microsoft Learn bis zu 20 Anfragen in einem einzigen Aufruf an /$batch.
- Die id jeder Anfrage verbindet sie mit ihrer Antwort. Die Antworten können in anderer Reihenfolge zurückkommen, deshalb sortiert das Skript nach id.
- Ein 200 für den Batch heißt nicht, dass jede Teilanfrage geklappt hat. Prüfe immer den
statusjeder einzelnen Antwort, im Beispiel liefert ein unbekannter Benutzer 404. - Drosselung gilt pro Teilanfrage: Jede wird einzeln gegen die Limits gezählt und kann mit 429 abgelehnt werden. Wie du darauf reagierst, steht in der Dokumentation zur Drosselung.
- Mehr als 20 Einträge teilst du in Pakete zu je 20 auf.
Troubleshooting: Typische Fehler
Request_UnsupportedQuery
- Du nutzt
endsWith,neodernotohneConsistencyLevel: eventualund$count=true. Beides gehört zusammen. - Die Eigenschaft ist schlicht nicht filterbar. Dann hilft auch die erweiterte Abfrage nicht, also lokal filtern.
Leere Ergebnisse, obwohl Geräte da sind
- Du suchst ein Intune-Gerät unter
/devicesoder umgekehrt. - Du verknüpfst
azureADDeviceIdmit deriddes Entra-Objekts statt mit dessendeviceId. - Der Filterwert ist falsch geschrieben, etwa
'NonCompliant'statt'noncompliant'. Nimm die Werte genau so, wie die Ressourcenbeschreibung sie auflistet.
Felder sind leer
departmentbleibt leer, wenn du nurUser.ReadBasic.Allhast oder das Feld im Verzeichnis nicht gepflegt ist.- Die Eigenschaft fehlt in deinem
$select. Graph liefert nur, was du anforderst.
$count ist nicht in der Antwort
- Ohne
ConsistencyLevel: eventualignoriert Graph$count=truebei Verzeichnisobjekten laut Microsoft Learn einfach, statt einen Fehler zu melden. Prüfe also, ob deine Parameter wirklich gewirkt haben.
Best Practices
- Nur lesende Berechtigungen für Berichte. Ein Berichtsskript braucht nie ReadWrite.
- Immer
$selectsetzen und Paging einbauen, auch wenn dein Testmandant nur zehn Geräte hat. - Große Datenmengen einmal laden und lokal verknüpfen, statt in einer Schleife pro Gerät nachzufragen.
- Filterwerte und Operatoren aus der Ressourcenbeschreibung übernehmen. Was dort nicht steht, lokal mit
Where-Objectfiltern. - Berichte mit Datum im Dateinamen ablegen. So kannst du Entwicklungen über Wochen vergleichen.
- Personenbezogene Daten im Bericht sparsam halten und die CSV nicht offen auf einem Netzlaufwerk liegen lassen.
Fazit
Mit $select, $filter, den erweiterten Abfragen und etwas lokaler Logik wird aus Graph ein Werkzeug, das dir in Sekunden die Listen liefert, für die du im Portal Minuten brauchst. Der wichtigste Schritt ist, die drei Objektarten auseinanderzuhalten und sauber zu verknüpfen.
Zusammenfassend für deinen Workflow:
- Klären, ob du Intune-Geräte, Entra-Geräte oder Benutzer brauchst, und die passende Read-Berechtigung wählen.
- Filterbare Felder in der Ressourcenbeschreibung nachsehen, alles andere lokal filtern.
- Für endsWith, ne und not den Header ConsistencyLevel: eventual plus $count=true setzen.
- Daten einmal laden, per Hashtable verknüpfen und als CSV mit Datum exportieren.
In der nächsten Sektion gehst du vom Lesen zum Schreiben: Du erstellst Richtlinien automatisiert per Graph API und weist sie zu. Einen Überblick über alle Sektionen findest du auf der Seite Intune-Kurs.
Quellen
- Microsoft Learn: managedDevice auflisten
- Microsoft Learn: managedDevice-Ressourcentyp
- Microsoft Learn: Benutzer auflisten
- Microsoft Learn: Geräte auflisten
- Microsoft Learn: device-Ressourcentyp
- Microsoft Learn: Erweiterte Abfragefunktionen für Verzeichnisobjekte
- Microsoft Learn: Abfrageparameter
- Microsoft Learn: Der Abfrageparameter $filter
- Microsoft Learn: Paging der Microsoft Graph-Daten
- Microsoft Learn: JSON-Batching
- Microsoft Learn: Drosselung in Microsoft Graph