Tenable 150480 : corriger primaryGroupID=6604 dans Active Directory (guide PowerShell)

Une alerte Tenable “Primary Group ID Integrity” (plugin 150480) s’affiche sur vos 24 contrôleurs de domaine : des comptes AD ont un primaryGroupID positionné à 6604. Voici un guide concret, prêt à l’emploi, pour identifier, corriger et prévenir ce type d’écart.

Sommaire

Contexte et impact

Lors d’un scan Tenable sur les contrôleurs de domaine, le plugin AD Starter Scan – Primary Group ID Integrity remonte des objets Active Directory dont l’attribut primaryGroupID est positionné sur une valeur non standard : 6604. L’équipe souhaite savoir à quel groupe correspond ce RID (Relative Identifier), comment retrouver les comptes affectés et comment corriger l’attribut.

Points essentiels à retenir :

  • primaryGroupID est un entier qui représente le RID du groupe primaire d’un objet. Le SID complet du groupe primaire est <DomainSID>-<primaryGroupID>.
  • Les valeurs « saines » les plus communes sont : 513 = Domain Users (comptes utilisateurs), 515 = Domain Computers (comptes ordinateurs), 516 = Domain Controllers (contrôleurs de domaine). 512 = Domain Admins n’est pas le défaut d’un utilisateur ; l’utiliser comme groupe primaire est atypique et risqué.
  • Une valeur exotique (comme 6604) indique en général un script ou outil qui a modifié l’attribut de manière involontaire.

Ce que signifie vraiment primaryGroupID

Historiquement, le groupe primaire servait surtout à la compatibilité POSIX/SMB. Sur Windows, même si le groupe primaire n’apparaît pas forcément dans l’attribut memberOf de l’utilisateur, le SID du groupe primaire est quand même ajouté au jeton d’accès de l’utilisateur à l’ouverture de session. Conséquence : si vous fixez le groupe primaire sur un groupe à privilèges (ex. 512 = Domain Admins), vous conférez de fait ces privilèges, même si l’utilisateur n’est pas listé comme membre « classique » du groupe.

Type d’objetValeur par défaut du primaryGroupIDGroupe concernéRemarques
Utilisateur standard513Domain UsersValeur « saine » et attendue. Recommandée pour la quasi-totalité des comptes.
Ordinateur515Domain ComputersPour les comptes machine. À ne pas confondre avec des comptes utilisateurs de service.
Contrôleur de domaine516Domain ControllersÀ ne jamais écraser ; sinon démarrages et réplications peuvent être affectés.
Compte à privilèges513 recommandéDomain UsersÉvitez 512 = Domain Admins comme groupe primaire : cas très particulier et dangereux.

Pourquoi Tenable remonte la valeur 6604

Le RID 6604 n’est pas un RID « bien connu » d’Active Directory. Plusieurs origines possibles :

  • Un script d’intégration ou de migration (ADMT, provisioning, outil tiers IAM) a utilisé Set-ADUser -Replace @{primaryGroupID=<valeur>} avec un paramètre incorrect.
  • Une procédure de test a défini un groupe primaire personnalisé, puis le groupe cible a été supprimé. Les comptes gardent alors un primaryGroupID orphelin.
  • Erreur humaine via ADUC : bouton « Définir comme groupe principal » sur un groupe inadapté.

Identifier précisément les comptes affectés

Avant toute modification, faites l’inventaire : qui a primaryGroupID = 6604 ? De quel type d’objets s’agit-il (utilisateurs, ordinateurs, gMSA, etc.) ? À quel groupe correspond le RID 6604 dans votre domaine (s’il existe) ?

Lister tous les objets avec primaryGroupID = 6604

# Module requis : ActiveDirectory
# Utilisateurs
Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,Enabled,memberOf |
  Select-Object SamAccountName, Enabled, primaryGroupID, memberOf

# Ordinateurs

Get-ADComputer -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,Enabled |
Select-Object SamAccountName, Enabled, primaryGroupID

# Tous objets (utile pour voir des types inattendus)

Get-ADObject -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,objectClass,objectSid |
Select-Object Name, objectClass, primaryGroupID, objectSid 

Trouver à quel groupe correspond le RID 6604

Le groupe primaire est le groupe dont le SID se termine par le RID stocké dans primaryGroupID. Construisez le SID complet de domaine et cherchez un groupe dont le SID se termine par -6604 :

$domainSid = (Get-ADDomain).DomainSID.Value
$rid       = 6604
$targetSid = "$domainSid-$rid"

Get-ADGroup -Filter * | Where-Object { $_.SID.Value -eq $targetSid } |
Select-Object Name, DistinguishedName, SID 

Cas 1 : un groupe est trouvé — vous avez identifié la cible « réelle ».
Cas 2 : aucun groupe n’existe avec ce RID — vos comptes portent un groupe primaire orphelin ; il faut rétablir une valeur valide (513, 515, 516 selon le cas).

Exporter une preuve et préparer le rollback

Avant modification, exportez les objets concernés, leurs attributs clés et la date de dernière modification :

Get-ADObject -LDAPFilter "(primaryGroupID=6604)" -Properties * |
  Select-Object ObjectClass, SamAccountName, DistinguishedName, primaryGroupID, SID, whenChanged |
  Export-Csv .\PGID-6604-inventory.csv -NoTypeInformation -Encoding UTF8

Corriger de manière sûre et reproductible

Bonnes pratiques avant d’écrire

  • Fenêtre de changement approuvée et sauvegarde/export des objets ciblés.
  • Compte opérateur avec droits suffisants et session PowerShell en Run as domain admin.
  • Test sur un échantillon représentatif (1–3 comptes) avant exécution en masse.

Rétablir le groupe primaire des utilisateurs sur 513 = Domain Users

En plus d’ajuster primaryGroupID, vérifiez que le compte est bien membre de Domain Users (utile pour certains workflows et outils). Le script ci-dessous est idempotent :

$targets = Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID
foreach ($u in $targets) {
  try {
    Add-ADGroupMember -Identity "Domain Users" -Members $u -ErrorAction SilentlyContinue
    Set-ADUser -Identity $u -Replace @{primaryGroupID = 513}
    Write-Host "OK  - $($u.SamAccountName) → primaryGroupID=513"
  } catch {
    Write-Warning "NOK - $($u.SamAccountName): $($_.Exception.Message)"
  }
}

Rétablir le groupe primaire des ordinateurs sur 515 = Domain Computers

$targets = Get-ADComputer -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID
foreach ($c in $targets) {
  try {
    Add-ADGroupMember -Identity "Domain Computers" -Members $c -ErrorAction SilentlyContinue
    Set-ADComputer -Identity $c -Replace @{primaryGroupID = 515}
    Write-Host "OK  - $($c.SamAccountName) → primaryGroupID=515"
  } catch {
    Write-Warning "NOK - $($c.SamAccountName): $($_.Exception.Message)"
  }
}

Que faire pour des comptes à privilèges ?

  • Recommandation : conserver 513 = Domain Users comme groupe primaire, même pour des administrateurs. L’appartenance au groupe Domain Admins doit rester gérée via l’attribut memberOf, pas via le groupe primaire.
  • À éviter : définir 512 = Domain Admins comme groupe primaire d’un compte non critique ; c’est atypique, source de confusion et potentiellement dangereux.

Contrôleurs de domaine

Pour les objets computer qui sont des DC, la valeur doit être 516 (Domain Controllers). Ne touchez pas aux DC si l’alerte concerne uniquement des comptes utilisateurs ; limitez votre périmètre aux objets inventoriés.

Validation post-correction

  1. Réplication AD : forcer une réplication inter-sites si nécessaire (repadmin /syncall /AdeP depuis un DC de référence).
  2. Jeton de l’utilisateur : ouvrez une session avec un compte corrigé et exécutez whoami /all pour vérifier les SIDs de groupes inclus dans le jeton.
  3. Relancer l’analyse Tenable : ciblez le domaine ou lancez un Rescan complet. Le plugin 150480 doit disparaître pour les objets corrigés.
  4. Journalisation : contrôlez vos logs (événements 4738/5136) pour tracer les changements d’attribut.

Automatiser la prévention

Mettez en place une surveillance récurrente (tâche planifiée) qui alerte dès qu’un primaryGroupID sort des bornes attendues par type d’objet :

# Paramétrage des valeurs "autorisées"
$allowed = @{
  user      = @(513)           # Domain Users
  computer  = @(515, 516)      # Domain Computers, Domain Controllers (rare côté computer)
  msDSGroupManagedServiceAccount = @(513) # gMSA assimilé à "user" côté logique
}

$bad = @()

# Collecte globale

$objs = Get-ADObject -LDAPFilter "(&(primaryGroupID=*)(!(isDeleted=*)))" -Properties objectClass, primaryGroupID, SamAccountName
foreach ($o in $objs) {
$cls = $o.objectClass.ToLower()
$pg  = [int]$o.primaryGroupID
if ($allowed.ContainsKey($cls)) {
if ($allowed[$cls] -notcontains $pg) { $bad += $o }
} else {
# Pour les classes non prévues, on considère "suspect"
$bad += $o
}
}

if ($bad.Count -gt 0) {
$bad | Select-Object objectClass, SamAccountName, DistinguishedName, primaryGroupID |
Export-Csv ".\PGID-outliers-$(Get-Date -Format yyyyMMdd-HHmm).csv" -NoTypeInformation
Write-Warning ("{0} objet(s) avec primaryGroupID inattendu. Rapport généré." -f $bad.Count)
} else {
Write-Host "Aucun écart détecté."
} 

Ajoutez ensuite une étape d’envoi (mail/Teams/Webhook) si le CSV contient des enregistrements.

Diagnostic avancé et causes racines

Pour comprendre l’origine de la valeur 6604 :

  • Audit Directory Service Changes : activez l’audit avancé si ce n’est pas déjà fait.
  • Recherche d’événements : # Événements 4738 (user account changed) et 5136 (modification d'objet AD) Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4738} | Where-Object { $_.Message -like "*Primary Group ID*" } | Select-Object TimeCreated, Id, Message | Out-GridView Get-WinEvent -FilterHashtable @{LogName="Directory Service"; Id=5136} | Where-Object { $_.Message -like "*primaryGroupID*" } | Select-Object TimeCreated, Id, Message | Out-GridView
  • CIAM/IAM : vérifiez les connecteurs (ServiceNow, SailPoint, scripts de provisioning) qui pourraient écrire l’attribut directement.
  • Migration inter-domaines : certains outils copient des attributs tels quels ; après bascule, le RID peut ne plus référencer un groupe existant.

Tableau récapitulatif des actions

ObjectifActions recommandéesCommentaires pratiques
Identifier les comptes affectésRechercher les objets où primaryGroupID = 6604.Ex. PowerShell : Get-ADUser -Filter 'PrimaryGroupID -eq 6604' -Properties PrimaryGroupID
Comprendre la valeur sûreUtilisateurs : 513 = Domain Users.
Ordinateurs : 515 = Domain Computers.
DC : 516 = Domain Controllers.
Évitez 512 sauf cas très spécifiques et entièrement maîtrisés.
Rétablir l’ID de groupe primaireSet-ADUser -Identity <UserDN> -Replace @{primaryGroupID=513}Exécuter sous un compte ayant des droits d’administration du domaine.
Valider la correctionForcer la réplication AD, tester whoami /all, relancer un scan Tenable.Attendez la convergence avant de conclure.
Documentation et préventionDocumenter la cause racine et déployer une alerte automatique sur les outliers de primaryGroupID.Réduit fortement le risque de régression.

Exemples « copier-coller » prêts pour l’exploitation

Inventaire rapide (utilisateurs) + export

Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties * |
  Select-Object SamAccountName, Name, Enabled, primaryGroupID, whenChanged, lastLogonDate, memberOf |
  Export-Csv .\PGID-6604-users.csv -NoTypeInformation -Encoding UTF8

Correction en lot avec sauvegarde des valeurs initiales

$snapshot = Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID |
  Select-Object SamAccountName, DistinguishedName, primaryGroupID
$snapshot | Export-Csv .\PGID-6604-users-backup.csv -NoTypeInformation

foreach ($u in $snapshot) {
try {
Add-ADGroupMember -Identity "Domain Users" -Members $u.DistinguishedName -ErrorAction SilentlyContinue
Set-ADUser -Identity $u.DistinguishedName -Replace @{primaryGroupID=513}
Write-Host "OK  - $($u.SamAccountName) réparé"
} catch {
Write-Warning "NOK - $($u.SamAccountName): $($_.Exception.Message)"
}
} 

Vérification post-changement

Get-ADUser -LDAPFilter "(primaryGroupID=513)" -Properties primaryGroupID |
  Where-Object {$_.whenChanged -gt (Get-Date).AddHours(-4)} |
  Select-Object SamAccountName, primaryGroupID, whenChanged

Questions fréquentes

Changer primaryGroupID modifie-t-il l’appartenance aux groupes ?
L’attribut ne met pas à jour l’attribut memberOf des groupes, mais le SID du groupe primaire est injecté dans le jeton. Fonctionnellement, il est donc traité comme une appartenance pour le contrôle d’accès. D’où la prudence : ne définissez pas un groupe primaire à privilèges par inadvertance.

Pourquoi ne pas mettre 512 pour un administrateur ?
Même pour des admins, il est plus simple, sûr et auditable de conserver 513 comme primaire et de gérer les privilèges via memberOf (Domain Admins). La valeur 512 comme primaire rend les analyses et audits plus confus et n’apporte aucun bénéfice concret.

Que faire si le groupe au RID 6604 n’existe plus ?
Rétablissez le primaire sur une valeur valide (513/515/516 selon l’objet). Vous ne pouvez pas recréer un groupe avec un RID précis : les RID sont attribués par le RID Master.

Est-ce que l’alerte ciblant les DC signifie que les DC sont en cause ?
Pas forcément. Tenable interroge l’annuaire en s’appuyant sur les DC ; l’alerte met en évidence des objets du domaine (utilisateurs/ordinateurs) avec une valeur non standard, pas nécessairement les comptes machine des DC.

Runbook express

  1. Inventorier les objets avec primaryGroupID=6604 et exporter la liste.
  2. Identifier le groupe cible via le SID <DomainSID>-6604 (s’il existe).
  3. Corriger : utilisateurs → 513, ordinateurs → 515, DC → 516. Ne pas utiliser 512 sauf justificatif.
  4. Forcer la réplication et retester (whoami /all, rescan Tenable).
  5. Documenter la cause racine et déployer la surveillance automatisée.

Résultat attendu

  • Après remise sur 513 (ou 515/516 selon l’objet) et rescan, le plugin 150480 n’apparaît plus.
  • La cause racine est consignée (script, outil tiers, migration) et une alerte empêche la réapparition de valeurs exotiques.

Exemples supplémentaires utiles

Identifier tous les groupes « bien connus » pour votre domaine

Utile pour créer une matrice de valeurs autorisées adaptée à votre environnement :

$knownRids = 512..521 + 513 + 515 + 516
$domainSid = (Get-ADDomain).DomainSID.Value

$knownGroups = foreach ($rid in ($knownRids | Select-Object -Unique)) {
$sid = "$domainSid-$rid"
Get-ADGroup -Filter * | Where-Object { $_.SID.Value -eq $sid } |
Select-Object Name, SID
}
$knownGroups | Format-Table -Auto 

Repérer des comptes dominants par erreur

Détecte les comptes dont le groupe primaire serait à privilèges (ex. 512) :

Get-ADUser -LDAPFilter "(primaryGroupID=512)" -Properties SamAccountName,primaryGroupID |
  Select-Object SamAccountName, primaryGroupID

Restaurer une valeur incohérente au cas par cas

Réglage manuel pour un compte utilisateur précis :

Set-ADUser -Identity "CN=Jean Dupont,OU=Users,DC=exemple,DC=local" `
  -Replace @{primaryGroupID=513}

Checklist de qualité avant clôture

  • Inventaire initial archivé et daté.
  • Scripts, journaux d’exécution et éventuels messages d’erreur conservés.
  • Preuve de réplication OK (repadmin sans erreur).
  • Preuve fonctionnelle (whoami /all sur un compte corrigé).
  • Rapport Tenable après rescan avec statut « remédié ».
  • Surveillance planifiée en place (tâche planifiée, alerting).

Conclusion

Un primaryGroupID non standard (ex. 6604) signale une anomalie de configuration. La correction est simple : remettre la valeur par défaut selon le type d’objet, forcer la réplication et valider par scan. Le volet essentiel est la prévention : outillez la détection d’outliers et clarifiez vos procédures de provisioning pour éviter qu’un script ne réécrive l’attribut par erreur.


Annexe – valeurs typiques des RID utiles (rappel, non exhaustif)

RIDGroupeUsage
512Domain AdminsGroupe à privilèges élevés (éviter comme groupe primaire).
513Domain UsersDéfaut des utilisateurs.
515Domain ComputersDéfaut des comptes machine.
516Domain ControllersDéfaut des DC.
517Cert PublishersComptes liés à l’AD CS.
520Group Policy Creator OwnersGestion avancée des GPO (utilisation rare).
521Denied RODC Password Replication GroupRODC – liste de déni de réplication de mots de passe.

En appliquant ces étapes — inventaire, correction ciblée, validation et prévention — vous éliminez l’alerte Tenable 150480 de manière durable tout en renforçant la sécurité et la maintenabilité de votre annuaire.

Sommaire