Le blog technique

Toutes les astuces #tech des collaborateurs de PI Services.

#openblogPI

Retrouvez les articles à la une

[Entra ID] Récupération des différents types de sign-in pour un audit de sécurité

Lors d’un audit de sécurité Entra ID (Azure AD), il est essentiel de distinguer les différents types de connexions afin d’avoir une vision claire des usages et d’identifier les connexions suspectes ou inutiles. Microsoft Graph centralise ces informations, mais elles ne sont pas toujours triviales à exploiter directement.

En pratique, quatre types principaux de sign-ins sont à connaître :

  • Interactive user
    Une connexion initiée par un utilisateur réel, typiquement via le portail Microsoft 365, Outlook, Teams ou un autre service nécessitant l’authentification interactive.
    Ces sign-ins sont soumis aux politiques MFA et aux conditions d’accès.

  • Non-interactive user
    Une connexion réalisée par un utilisateur, mais sans interaction directe, souvent pour des scripts, applications ou services automatisés utilisant un mot de passe ou un token stocké.
    Exemples : tâches planifiées, scripts PowerShell ou outils tiers accédant à Exchange ou SharePoint via un compte utilisateur.

  • Service Principal (SPN)
    Une authentification effectuée par une application enregistrée dans Entra ID. Les SPN sont utilisés par des services et scripts qui se connectent au nom de l’application, indépendamment d’un utilisateur.
    Exemples : intégrations SaaS, scripts automatisés via une App Registration, pipelines CI/CD.

  • Managed Identity
    Utilisée par les ressources Azure (VM, Functions, App Service, etc.) pour s’authentifier automatiquement auprès d’Azure AD sans gérer de credentials.
    Ces identités sont sécurisées, éphémères et ne nécessitent pas de mot de passe stocké.

Microsoft Graph ne propose pas un filtre unique pour tous les distinguer facilement. Pour obtenir une vue précise, il faut filtrer les sign-ins selon l’attribut signInEventTypes.

Prérequis

Commandes PowerShell par type de sign-in

Pour récupérer les sign-ins d’une application ou d’un utilisateur, on utilise la cmdlet Get-MgBetaAuditLogSignIn avec un filtre sur signInEventTypes :

$StartDate = (Get-Date).AddDays(-30)
$Application = Get-MgApplication -Filter "DisplayName eq 'MonApp'"

# Interactive
Get-MgBetaAuditLogSignIn -Filter "AppId eq '$($Application.AppId)' and createdDateTime ge $StartDate and signInEventTypes/any(t: t eq 'interactiveUser')"

# Non-interactive
Get-MgBetaAuditLogSignIn -Filter "AppId eq '$($Application.AppId)' and createdDateTime ge $StartDate and signInEventTypes/any(t: t eq 'nonInteractiveUser')"

# Service Principal
Get-MgBetaAuditLogSignIn -Filter "AppId eq '$($Application.AppId)' and createdDateTime ge $StartDate and signInEventTypes/any(t: t eq 'servicePrincipal')"

# Managed Identity
Get-MgBetaAuditLogSignIn -Filter "AppId eq '$($Application.AppId)' and createdDateTime ge $StartDate and signInEventTypes/any(t: t eq 'managedIdentity')"

[REX] Erreur lors de l’import d’un module : gérer les versions multiples

PowerShell repose largement sur des modules pour étendre ses fonctionnalités, que ce soit pour l’administration système, la gestion Microsoft 365 ou des scripts internes. Dans de nombreux environnements, il arrive qu’un même module soit présent en plusieurs versions sur la machine, ce qui peut générer des conflits lors de l’import dans un script.

Ce problème se manifeste souvent lorsque l’on écrit ou exécute des scripts sur différentes machines ou environnements, par exemple :

  • un script utilisant Exchange Online ou Microsoft.Graph sur des serveurs différents
  • plusieurs versions d’un module interne développé en interne pour automatiser l’inventaire ou la configuration
  • des mises à jour partielles qui laissent des versions anciennes et nouvelles sur la machine

Dans ces cas, l’exécution d’un Import-Module peut échouer ou charger la mauvaise version, entraînant des erreurs inattendues ou des comportements incompatibles.

Exemples typiques :

  • Import-Module : Module 'PnP.PowerShell' is already loaded.
  • Des cmdlets manquantes ou modifiées entre versions
  • Conflits de dépendances entre modules
  • Scripts fonctionnant en test mais échouant en production

Ces erreurs surviennent car PowerShell charge par défaut la première version trouvée dans le $env:PSModulePath, sans vérifier la compatibilité de version avec le script.

La gestion des versions de module est un élément souvent sous-estimé :

  • Chaque version peut contenir des cmdlets différentes, ou modifier le comportement existant
  • Certains modules ne supportent pas la cohabitation de plusieurs versions dans la même session
  • Les scripts automatisés peuvent être sensibles à la version exacte pour des raisons de compatibilité ou de sécurité

Solutions et bonnes pratiques

  1. Spécifier la version souhaitée lors de l’import

Pour éviter les conflits, utilisez -RequiredVersion pour charger exactement la version nécessaire :

Import-Module -Name PnP.PowerShell -RequiredVersion 1.12.0

Si le script peut tolérer plusieurs versions récentes, utilisez -MinimumVersion et/ou -MaximumVersion pour définir une plage compatible :

Import-Module -Name PnP.PowerShell -MinimumVersion 1.10.0 -MaximumVersion 1.12.0
  1. Vérifier les versions installées avant import
Get-InstalledModule -Name PnP.PowerShell -AllVersions

Cela permet d’identifier les versions présentes et de planifier une mise à jour ou un nettoyage si nécessaire.

  1. Forcer le rechargement si un module est déjà chargé

Lorsque PowerShell détecte une version chargée, certaines cmdlets peuvent provoquer des erreurs. -Force permet de recharger la version spécifiée :

Import-Module -Name PnP.PowerShell -RequiredVersion 1.12.0 -Force
  1. Importer via le chemin complet du module

Pour un contrôle absolu et éviter tout conflit avec d’autres versions présentes dans $env:PSModulePath :

Import-Module "C:\Program Files\WindowsPowerShell\Modules\PnP.PowerShell\1.12.0\PnP.PowerShell.psd1"
  1. Limiter le scope de l’import

En utilisant -Scope CurrentUser ou -Scope LocalSession, on peut isoler le module à la session ou à l’utilisateur, réduisant les conflits avec d’autres scripts ou administrateurs :

Import-Module -Name PnP.PowerShell -RequiredVersion 1.12.0 -Scope CurrentUser

[Entra ID / Hybrid Identity] Mot de passe valide en AD On-Prem mais expiré dans Entra ID

Le problème est apparu avec des comptes de service on-premises, configurés avec une PSO Active Directory autorisant une validité de mot de passe étendue (1 an). Ces comptes étaient synchronisés vers Entra ID via Azure AD Connect, ce qui est une pratique courante pour des scripts, services ou tâches hybrides.

Côté Entra ID, en revanche, la politique de mot de passe par défaut impose une expiration à 90 jours. Contrairement à AD on-prem, il n’est pas possible d’appliquer une politique de mot de passe spécifique à un utilisateur ou un groupe sans impacter l’ensemble du tenant.

Résultat : le mot de passe reste parfaitement valide on-prem, mais Entra ID le considère comme expiré.

Les symptômes sont trompeurs :

  • le compte n’est pas bloqué
  • l’authentification on-prem fonctionne
  • mais toute tentative d’accès cloud (M365, Graph, Exchange Online, SharePoint, etc.) échoue

Ce scénario devient critique lorsque le compte de service on-prem initie une connexion vers le cloud : scripts PowerShell, tâches planifiées, flux hybrides.., tout casse silencieusement à cause de l’expiration côté Entra ID.

Après analyse, le comportement est logique : Entra ID ne tient pas compte des PSO on-premises pour l’expiration du mot de passe. L’état du mot de passe est évalué selon les règles cloud, indépendamment de sa validité dans AD.

La solution consiste donc à désactiver explicitement l’expiration du mot de passe côté Entra ID pour ces comptes spécifiques. Cela se fait via Microsoft Graph en positionnant la propriété, passwordPolicies à DisablePasswordExpiration.

Commande PowerShell :

Update-MgUser -UserId $UserId -PasswordPolicies "DisablePasswordExpiration"

Cette configuration permet :

  • de conserver une PSO stricte et contrôlée on-prem
  • d’éviter toute expiration côté cloud
  • de sécuriser les scénarios hybrides et automatisés

Cette approche doit évidemment rester limitée aux comptes de service et documentée clairement, mais elle s’avère indispensable dans de nombreux environnements hybrides réels.