- Microsoft Graph
- PowerShell
- Entra ID
Warum Update-MgUser beim Deaktivieren scheitert
Ein Einzeiler aus dem Offboarding, der nicht läuft, und was die Fehlermeldung über das Graph PowerShell SDK verrät.
Der Schritt ist der unspektakulärste im ganzen Offboarding: ein Konto deaktivieren. Ein Attribut, ein Wert, fertig. Ich habe das im JML-Lab so getippt, wie man es tippen würde:
Update-MgUser -UserId $id -AccountEnabled $falseUnd bekam: „A positional parameter cannot be found that accepts argument 'False'.“ Keine Berechtigungsmeldung, kein Hinweis auf ein fehlendes Scope. Eine Parser-Meldung, also noch bevor überhaupt ein Request an Graph rausgegangen ist.
Was die Meldung tatsächlich sagt
„Positional parameter cannot be found“ ist eine der eindeutigsten Fehlermeldungen von PowerShell. Sie bedeutet: Es gab ein Argument zu viel, für das kein benannter Parameter mehr übrig war, und es passte auch auf keine Position. Übersetzt auf den Einzeiler: PowerShell hat -AccountEnabled verarbeitet, war damit fertig, und stand dann mit $false alleine da.
Das passiert genau dann, wenn ein Parameter kein Wert-Parameter ist, sondern ein Schalter. Ein Schalter nimmt seinen Wert nicht als nächstes Token entgegen; seine bloße Anwesenheit bedeutet „wahr“. Das nachfolgende $false ist dann kein Wert mehr, sondern ein herrenloses Argument.
Nachprüfen lässt sich das in der eigenen Modulversion mit einer Zeile:
(Get-Command Update-MgUser).Parameters['AccountEnabled'].ParameterTypeZwei Wege, die funktionieren
Der erste ist die Doppelpunkt-Syntax. Sie ist die offizielle Art, einem Schalter explizit einen Wert zuzuweisen, und sie ist in PowerShell überall gültig, nicht nur hier:
Update-MgUser -UserId $id -AccountEnabled:$falseDer zweite geht am Parameter-Binding vorbei und schickt den Request-Body direkt. Genau so, wie ihn die Graph-API ohnehin erwartet:
Update-MgUser -UserId $id -BodyParameter @{ AccountEnabled = $false }Ich verwende in Skripten inzwischen durchgehend die zweite Variante. Nicht weil die erste falsch wäre, sondern weil sie eine Eigenschaft hat, die man leicht übersieht: Ein einziger vergessener Doppelpunkt kehrt das Ergebnis ins Gegenteil um. -AccountEnabled $false bricht wenigstens laut ab. -AccountEnabled alleine, etwa nach einem hastigen Refactoring, läuft durch und aktiviert das Konto, das gerade deaktiviert werden sollte. Ein Offboarding-Skript, das still das Gegenteil tut, ist deutlich schlimmer als eines, das abbricht.
Woher das kommt
Das Microsoft.Graph-Modul ist nicht von Hand geschrieben, sondern aus der OpenAPI-Beschreibung der Graph-API generiert. Was man in der Konsole vor sich hat, ist also eine maschinelle Übersetzung eines REST-Endpunkts in Cmdlet-Form. Diese Übersetzung ist an vielen Stellen bequem. An einigen wenigen eben nicht eins zu eins.
Praktisch heißt das dreierlei. Erstens ist die Graph-Dokumentation für den Request-Body immer die verlässlichere Quelle als die Cmdlet-Signatur. Zweitens können sich generierte Signaturen zwischen Modulversionen ändern, weshalb Get-Command vor dem Debuggen schneller ist als eine Suchmaschine. Drittens ist -BodyParameter kein Notausgang, sondern der direktere Weg: eine Hashtable, die eins zu eins dem JSON entspricht, das ohnehin über die Leitung geht.
Das Ganze hat mich vielleicht zwanzig Minuten gekostet. Erwähnenswert finde ich es trotzdem, weil in keinem Kurs steht, dass ein Boolean im generierten SDK ein Schalter sein kann. Das lernt man, wenn man es selbst tippt und dagegen läuft.