Inhalt

Operator mvexpand: expanded expression expected to have dynamic type

TIL; Today I Learned

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…

1
2
3
4
5
6
let ConditionalAccessPolicyId = "f06e5e30-0c18-493f-9d21-b69aaa44248a";
SigninLogs
| where UserPrincipalName == "fabian@bader.cloud"
| mv-expand ConditionalAccessPolicies
| where ConditionalAccessPolicies.id == ConditionalAccessPolicyId
| project TimeGenerated, UserPrincipalName, AppDisplayName, ConditionalAccessStatus, ConditionalAccessPolicies.displayName, ConditionalAccessPolicies.result

/til-operator-mvexpand-expanded-expression-expected-dynamic-type/images/SignInQuerySuccessfull.png

…schlägt dieselbe Abfrage fehl, wenn man die Tabelle auf AADNonInteractiveUserSignInLogs ändert.

1
2
3
4
5
6
let ConditionalAccessPolicyId = "f06e5e30-0c18-493f-9d21-b69aaa44248a";
AADNonInteractiveUserSignInLogs
| where UserPrincipalName == "fabian@bader.cloud"
| mv-expand ConditionalAccessPolicies
| where ConditionalAccessPolicies.id == ConditionalAccessPolicyId
| project TimeGenerated, UserPrincipalName, AppDisplayName, ConditionalAccessStatus, ConditionalAccessPolicies.displayName, ConditionalAccessPolicies.result

/til-operator-mvexpand-expanded-expression-expected-dynamic-type/images/errormessage.png

Fehler
Operator mvexpand: expanded expression expected to have dynamic type
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.

/til-operator-mvexpand-expanded-expression-expected-dynamic-type/images/DifferenceInAttributeType.png

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.

1
2
3
4
5
6
7
let ConditionalAccessPolicyId = "f06e5e30-0c18-493f-9d21-b69aaa44248a";
AADNonInteractiveUserSignInLogs
| where UserPrincipalName == "fabian@bader.cloud"
| extend ConditionalAccessPolicies = todynamic(ConditionalAccessPolicies)
| mv-expand ConditionalAccessPolicies
| where ConditionalAccessPolicies.id == ConditionalAccessPolicyId
| project TimeGenerated, UserPrincipalName, AppDisplayName, ConditionalAccessStatus, ConditionalAccessPolicies.displayName, ConditionalAccessPolicies.result

/til-operator-mvexpand-expanded-expression-expected-dynamic-type/images/NonInteractiveSignInQuerySuccessfull.png

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