15/11/2024

Utiliser PowerShell pour identifier les ordinateurs et utilisateurs inactifs

I. Présentation

On crée des utilisateurs, on ajoute des postes de travail et des serveurs au domaine, mais l’opération inverse est moins évidente : est-ce que l’on pense à nettoyer son annuaire Active Directory ? Notamment, afin d’identifier et de gérer les ordinateurs et les utilisateurs inactifs. D’une part, ceci permettra d’avoir un annuaire à jour, et d’autre part ceci évite de laisser des comptes actifs s’ils ne sont plus utilisés : un risque en termes de sécurité.

Dans son document « Recommandations de sécurité relatives à Active Directory », l’ANSSI recommande d’appliquer les règles suivantes pour la gestion des comptes inactifs, notamment pour vos utilisateurs :

  • Définir une politique de désactivation automatique des comptes non utilisés pendant un certain laps de temps
  • Conserver les comptes désactivés et inutilisés afin d’avoir un historique des comptes utilisateurs au sein du système d’information
  • Placer les comptes désactivés dans une unité d’organisation (« OU ») spécifique
  • Retirer les droits et privilèges des comptes désactivés

Passons maintenant à la pratique pour rechercher les objets inactifs, puis dans un second temps nous verrons comment gérer ces objets.

II. Comment identifier les utilisateurs inactifs ?

Pour atteindre notre objectif, on va s’appuyer sur le cmdlet nommé "Search-ADaccount". Il va permettre de rechercher les objets inactifs au sein de l'annuaire Active Directory, que ce soit les utilisateurs, mais également les ordinateurs.

Dans ce cmdlet, Le paramètre Timespan sert à indiquer un nombre de jours, par exemple si l'on indique 180 jours (6 mois) : la requête nous retournera les objets inactifs depuis au moins 180 jours. Grâce à ce cmdlet, nous allons pouvoir obtenir la liste des utilisateurs inactifs assez facilement.

Pour rechercher les comptes utilisateurs inactifs depuis 180 jours :

Search-ADaccount -UsersOnly -AccountInactive -Timespan 180

Attention, les comptes qui ne se sont jamais connectés seront considérés comme étant inactifs. Autrement dit, un compte qui vient d’être créé sera considéré comme inactif.

Cette commande va probablement retourner certains comptes built-in comme étant inactifs, par exemple le compte "Invité" ou le compte "krbtgt" qui sert à distribuer les tickets Kerberos. Pour éviter une mésaventure, il peut être intéressant d'exclure de la recherche l'OU "Users". Ce qui nous donne :

Search-ADaccount -UsersOnly -AccountInactive -Timespan 180 | Where{ $_.DistinguishedName -notmatch "CN=Users" }

Ah oui, au fait, j'allais oublier : nous allons ajouter une autre condition dans la clause Where pour récupérer uniquement les comptes activés dans l'annuaire. Il n’y a pas d’intérêt à ce que la commande retourne les comptes désactivés, car il y a des chances qu’ils soient déjà gérés.

Voici la commande mise à jour pour récupérer seulement les comptes actifs :

Search-ADaccount -UsersOnly -AccountInactive -Timespan 180 | Where{ ($_.DistinguishedName -notmatch "CN=Users") -and ($_.Enabled -eq $true) }

Maintenant que l’on est en mesure d’identifier les utilisateurs inactifs, faisons de même avec les ordinateurs.

III. Comment identifier les ordinateurs inactifs ?

Sur le même principe que pour les utilisateurs, nous allons utiliser le cmdlet « Search-ADaccount ». La différence, c’est que le paramètre -UsersOnly sera remplacé par -ComputersOnly pour s’intéresser aux objets ordinateurs.

Pour rechercher les comptes ordinateurs inactifs depuis 180 jours :

Search-ADaccount -ComputersOnly -AccountInactive -Timespan 180

Cette commande retournera également les éventuels gMSA (Group Managed Service Account) inactifs bien qu’ils aient une classe différente au niveau de l’Active Directory : « msDS-GroupManagedServiceAccount » contre la classe « computer » pour les objets ordinateurs.

Ce qui m’amène à vous suggérer d’appliquer un filtre supplémentaire sur la commande pour conserver seulement les objets avec la classe « computer », comme ceci :

Search-ADaccount -ComputersOnly -AccountInactive -Timespan 180 | Where{ $_.objectClass -eq "computer" }

Cette commande vous donnera la liste des ordinateurs inactifs depuis 180 jours ou plus. Quand je dis « ordinateurs », je fais référence aux postes de travail, aux serveurs et aux contrôleurs de domaines puisqu’ils s’appuient tous sur la classe « computer ».

IV. Les options complémentaires de Search-ADAccount

Le cmdlet Search-ADAccount, que nous utilisons depuis le début de ce chapitre dispose d’autres paramètres qui vont permettre d’identifier les comptes dans différents états, et pas seulement les comptes inactifs.

Voici des informations au sujet de ces paramètres, que je vous invite à tester sur le même principe que -AccountInactive :

Nom du paramètre Description
-AccountExpired Identifier les comptes expirés, c’est-à-dire les comptes qui ont une date d’expiration définie et qu’elle est passée.
-AccountDisabled Identifier les comptes désactivés.
-AccountExpiring Identifier les comptes qui vont expirer dans les X prochaines heures ou à partir d’une date spécifique. Implique l’utilisation de -DateTime ou -TimeSpan en complément.
-LockedOut Identifier les comptes bloqués, suite à trop de tentatives de connexion avec un mauvais mots de passe, par exemple.
-PasswordExpired Identifier les comptes dont le mot de passe est expiré.
-PasswordNeverExpires Identifier les comptes où le mot de passe n’expire jamais.

V. Search-ADAccount : comment exclure les nouveaux objets ?

Lorsque l’on utilise le cmdlet Search-ADAccount avec le paramètre -AccountInactive, on risque d’avoir des faux positifs. En effet, si l’on vient de créer un compte pour un utilisateur et que l’on exécute cette commande, le compte sera considéré comme étant inactif. L’attribut « lastLogon » sera vide, car l’utilisateur ne s’est pas encore connecté, ce qui explique ce cas de figure.

Pour éviter les faux positifs, il faut que l’on effectue un filtre complémentaire sur la commande Search-ADAccount. Malheureusement, la commande ne remonte pas la propriété « whenCreated » des objets : dommage, cela aurait pu nous simplifier la tâche pour détecter si un utilisateur a été créé récemment ou non.

Nous allons nous adapter et faire usage d’une boucle Foreach pour filtrer le résultat de la commande Search-ADAccount. Ce qui donne le bout de code suivant pour exclure aussi bien les nouveaux utilisateurs que les nouveaux ordinateurs.

$InactivesObjects = Search-ADaccount -AccountInactive -Timespan 180 | Where{ ($_.DistinguishedName -notmatch "CN=Users") -and ($_.Enabled -eq $true) } | foreach{

        if(($_.objectClass -eq "user") -and (Get-ADUser -Filter "Name -eq '$($_.Name)'" -Properties WhenCreated).WhenCreated -lt (Get-Date).AddDays(-7)){ $_ }
        if(($_.objectClass -eq "computer") -and (Get-ADComputer -Filter "Name -eq '$($_.Name)'" -Properties WhenCreated).WhenCreated -lt (Get-Date).AddDays(-7)){ $_ }

}

Dans l’exemple ci-dessus, on fait une exclusion des comptes créés sur les 7 derniers jours. Pour ajuster ce seuil, il suffit de modifier la valeur de la méthode « AddDays(-7) ». Remplacez le « 7 » par le chiffre que vous souhaitez, mais veillez à bien laisser le signe moins devant, il est nécessaire pour soustraire X jours à la date actuelle.

VI. Retirer l'utilisateur des groupes dont il est membre

Dans la suite de ce chapitre, je vais m’intéresser plus particulièrement aux utilisateurs afin de vous aider à appliquer les recommandations de l’ANSSI.

Ainsi, maintenant que nous sommes en capacité de récupérer la liste des objets inactifs, nous devons le supprimer des groupes auxquels il appartient. Prenons l'exemple d'un utilisateur nommé "une-comptable-01" et qui appartient à deux groupes : "Comptabilité" et "Utilisateurs du domaine". Nous allons lui laisser seulement le groupe par défaut, à savoir le groupe « Utilisateurs du domaine ».

Commençons par stocker le SamAccountName de l'utilisateur dans une variable :

$SamAccountName = "ma-comptable-01"

Puis, nous allons le retirer des groupes grâce à la commande ci-dessous :

Get-AdPrincipalGroupMembership -Identity $SamAccountName | Where-Object { $_.Name -Ne "Utilisateurs du domaine" } | Remove-AdGroupMember -Members $SamAccountName -Confirm:$false

Nous ne demanderons pas de confirmation pour plus de simplicité. Le tour est joué !

VII. Désactiver l'utilisateur et le déplacer

L’utilisateur est identifié, il n’est plus membre des groupes spécifiques auxquels il appartenait, il est temps désormais de le désactiver. Pour réaliser cette action, la commande Set-ADUser sera bien utile :

Set-ADUser -Identity $SamAccountName -Enabled:$false -Description "Désactivé le $(Get-Date -Format dd/MM/yyyy)"

Profitons-en pour mettre à jour la description de cet utilisateur en intégrant dans l'attribut "description", la date à laquelle nous l’avons désactivé afin d'avoir une traçabilité ?

Il ne reste plus qu’à isoler cet utilisateur dans une unité d’organisation dédiée aux comptes inactifs, que l’on pourrait qualifier de comptes archivés.

Avec le cmdlet Move-ADObject, nous allons utiliser le DistinguishedName de l'utilisateur, via la variable $DN. Cette valeur sera récupérée automatiquement dans le script final que je vous propose ci-dessous.

Par exemple :

$DN = "CN=Une Comptable,OU=Personnel,DC=IT-CONNECT,DC=LOCAL"

On déplace l'utilisateur vers l'OU "OU=Archivage,DC=IT-CONNECT,DC=LOCAL" :

Move-ADObject -Identity "$DN" -TargetPath "OU=Archivage,DC=IT-CONNECT,DC=LOCAL"

VIII. Script de gestion des comptes inactifs

Pour finir sur ce chapitre et maintenant que nous avons vu les différentes actions à réaliser traduites en commandes PowerShell, on peut regrouper tout cela dans un script afin de se simplifier la tâche.

Dans le but d’avoir un seul script qui gère aussi bien les ordinateurs que les utilisateurs inactifs, il faut penser à ne pas indiquer UsersOnly ou ComputersOnly dans la commande Search-ADAccount.

Il faut également adapter certaines commandes, en fonction de s'il s'agit un objet utilisateur ou ordinateur à traiter. Pour cela, on va se baser sur l'attribut ObjectClass qui nous indique si l'objet est de type user ou computer.

$InactivesObjects = Search-ADaccount -AccountInactive -Timespan 180 | Where{ ($_.DistinguishedName -notmatch "CN=Users") -and ($_.Enabled -eq $true) }

Foreach($Object in $InactivesObjects){

    $SamAccountName = $Object.SamAccountName
    $DN = $Object.DistinguishedName
    $ObjectClass = $Object.ObjectClass

    Write-Output "L'objet $SamAccountName est inactif !"

    # Si c'est un utilisateur...
    if($ObjectClass -eq "user"){

      # Retirer l'utilisateur des groupes (sauf "Utilisateurs du domaine")
      Get-AdPrincipalGroupMembership -Identity $SamAccountName | Where-Object { $_.Name -Ne "Utilisateurs du domaine" } | Remove-AdGroupMember -Members $SamAccountName -Confirm:$false -ErrorVariable ClearObject

      # Désactiver l'utilisateur
      Set-ADUser -Identity $SamAccountName -Enabled:$false -Description "Désactivé le $(Get-Date -Format dd/MM/yyyy)" -ErrorVariable +ClearObject

    # Sinon, si c'est un ordinateur...
    }elseif($ObjectClass -eq "computer"){

      # Retirer l'ordinateur des groupes (sauf "Ordinateurs du domaine")
      Get-AdPrincipalGroupMembership -Identity $SamAccountName | Where-Object { $_.Name -Ne "Ordinateurs du domaine" } | Remove-AdGroupMember -Members $SamAccountName -Confirm:$false -ErrorVariable ClearObject

      # Désactiver l'ordinateur
      Set-ADComputer -Identity $SamAccountName -Enabled:$false -Description "Désactivé le $(Get-Date -Format dd/MM/yyyy)" -ErrorVariable +ClearObject

    }

    # Déplacer l'utilisateur/ordinateur
    Move-ADObject -Identity "$DN" -TargetPath "OU=Archivage,DC=IT-CONNECT,DC=LOCAL" -ErrorVariable +ClearObject

    if($ClearUser){
      Write-Output "ERREUR ! objet concerné : $SamAccountName ($ObjectClass)"
    }else{
      Write-Output "Traitement de l'objet $SamAccountName de type $ObjectClass avec succès ! :-)"
    }

    Clear-Variable ClearUser
}

Ce script est fonctionnel et à votre disposition pour l’adapter selon vos besoins, notamment pour gérer uniquement les ordinateurs, ou les ordinateurs, ou alors ajouter l’envoi d’une notification si un compte est basculé en état « inactif ».

Actuellement, le script renvoie une sortie comme celle-ci :

Ce chapitre est terminé, il est temps de poursuivre dans la gestion des objets inutiles, inactifs, en s’intéressant de plus près à l’utilisation de la Corbeille Active Directory.

author avatar
Florian BURNEL Co-founder of IT-Connect
Ingénieur système et réseau, cofondateur d'IT-Connect et Microsoft MVP "Cloud and Datacenter Management". Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Envoyer par mail