Operator mvexpand: expanded expression expected to have dynamic type
TIL ist eine Blogreihe in der ich (für mich) interessante Erkenntnisse dokumentiere.
Diese Erkenntnisse ist eventuell schon hundertfach im Internet dokumentiert. Aber damit ich es wiederfinde habe ich es hier nochmal aufgeschrieben.
Microsoft bereitet seit einiger Zeit eine grundlegende Änderung der Anzeige und Speicherung von Sign-In Logs vor. Dies hilft bei der Analyse von Anmeldevorgängen, da z.B. unterschieden wird ob der Benutzer sich interaktiv oder mit einem gespeicherten Credential (non-interactive) anmeldet.
Die unterschiedlichen Typen sind:
- User sign-ins (interactive)
- User sign-ins (non-interactive)
- Service principal sign-ins
- Managed identity sign-ins
Wie Ihr eventuell schon in meiner Blogserie “Legacy Authentication kontrolliert abschalten” gelesen habt, bin ich ein großer Fan davon die Sign-In Informationen in einem Log Analytics workspace zu speichern. Es erleichtert die Abfrage der Daten ungemein und ermöglicht es komplexe Fragen mittels einfacherer, oder auch etwas komplexer, Abfragen zu beantworten.
Auch dort wird bei der Datenspeicherung zwischen den unterschiedlichen Sign-In Methoden unterschieden. Je nach Art werden die Daten in einer der folgenden Tabellen gespeichert:
- SignInLogs
- NonInteractiveUserSignInLogs
- ServicePrincipalSignInLogs
- ManagedIdentitySignInLogs
Das Problem
Dadurch bin ich auf ein Problem gestoßen; Während die folgende Abfrage für die Tabelle SigninLogs
ausgibt ob eine bestimmte Conditional Access Policy angewendet wird oder nicht…
|
|
…schlägt dieselbe Abfrage fehl, wenn man die Tabelle auf AADNonInteractiveUserSignInLogs
ändert.
|
|
Falls das Problem weiterhin besteht, öffnen Sie ein Supportticket.
Die Lösung
Die Lösung ist so einfach wie ärgerlich zuggleich. Microsoft hat leider bei der Implementiert der Tabellen unterschiedliche Datentypen gewählt.
Während in der Tabelle SignInLogs
die Eigenschaft ConditionalAccessPolicies
vom Typ dynamic
ist, wurde bei der Tabelle AADNonInteractiveUserSignInLogs
der Typ string
gewählt.
Als Workaround muss der Typ zur Laufzeit geändert werden. Das geht mit einem einfachen todynamic(ConditionalAccessPolicies)
in Zeile 4.
Der ursprüngliche Datentyp kann dazu einfach überschrieben werden. Das erleichtert die Entwicklung von Abfragen für alle Tabellen.
|
|
Erweiterte Analyse
Ich habe das komplette Schema analysiert und alle Unterschiede, die ich gefunden habe, hier dokumentiert.
SignIn-ColumnName | ColumnType | NonInt-ColumnName | ColumnType | Result |
---|---|---|---|---|
AADTenantId | string | Missing in AADNonInteractiveUserSignInLogs | ||
ConditionalAccessPolicies | dynamic | ConditionalAccessPolicies | string | Missing in AADNonInteractiveUserSignInLogs |
DeviceDetail | dynamic | DeviceDetail | string | Missing in AADNonInteractiveUserSignInLogs |
FlaggedForReview | bool | Missing in AADNonInteractiveUserSignInLogs | ||
HomeTenantId | string | Missing in AADNonInteractiveUserSignInLogs | ||
IPAddressFromResourceProvider | string | Missing in AADNonInteractiveUserSignInLogs | ||
LocationDetails | dynamic | LocationDetails | string | Different DataType |
MfaDetail | dynamic | MfaDetail | string | Different DataType |
ProcessingTimeInMilliseconds | string | ProcessingTimeInMs | string | Different property name |
Resource | string | Missing in AADNonInteractiveUserSignInLogs | ||
ResourceId | string | Missing in AADNonInteractiveUserSignInLogs | ||
ResourceProvider | string | Missing in AADNonInteractiveUserSignInLogs | ||
ServicePrincipalId | string | Missing in AADNonInteractiveUserSignInLogs | ||
ServicePrincipalName | string | Missing in AADNonInteractiveUserSignInLogs | ||
SignInIdentifier | string | Missing in AADNonInteractiveUserSignInLogs | ||
SignInEventTypes | string | Missing in SigninLogs | ||
SignInIdentifierType | string | Missing in AADNonInteractiveUserSignInLogs | ||
Status | dynamic | Status | string | Different DataType |
UserType | string | Missing in AADNonInteractiveUserSignInLogs |