Identifier qui a (ou n’a pas) reçu Genian NAC via GPO : audit, scripts PowerShell et dépannage

Besoin d’identifier rapidement quels postes ont bien reçu le client Genian NAC via GPO ? Voici une méthode complète, outillée et reproductible pour obtenir une liste claire des installations réussies et des échecs, avec des scripts PowerShell prêts à l’emploi et des conseils de dépannage.

Sommaire

Contexte et objectif

Vous avez déployé le client Genian NAC par Stratégie de Groupe (GPO). Certains postes l’ont reçu, d’autres non. L’objectif : produire un inventaire fiable « Installé / Non installé / Échec », comprendre pourquoi une machine n’a pas reçu l’agent, puis corriger et relancer le déploiement au besoin.

Plan de contrôle en quatre axes

  1. Vérifier l’application de la GPO (ciblage, filtrage de sécurité, WMI filter, héritage/liaison OU).
  2. Collecter les journaux d’installation (MSI et « Application Management »).
  3. Valider la présence réelle du logiciel sur les postes (registre d’installation).
  4. Consolider le tout dans un rapport unique (CSV/HTML) afin de prioriser les actions.

Vue d’ensemble : objectifs, méthodes et livrables

ObjectifMéthode recommandéeRésultat attendu
Connaître l’état d’application de la GPOUtiliser la Group Policy Management Console (GPMC) → Group Policy Results Wizard (ou RSoP). En masse, PowerShell Get-GPResultantSetOfPolicy ou gpresult.Rapport par machine/utilisateur indiquant si la GPO « Genian NAC » s’est appliquée et, sinon, la raison (filtrage de sécurité, WMI filter, problème de liaison OU, héritage bloqué, etc.).
Détecter les échecs d’installationObservateur d’événements (local ou distant). Filtrer les journaux Application : Application Management (ID 301–302) et MsiInstaller (ID 103–108, 117–119). Export en CSV (PowerShell ou wevtutil).Liste horodatée des PC où l’installation a démarré, réussi ou échoué (codes et messages à l’appui).
Vérifier la présence réelle du logicielRegistre d’installation : HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\* et HKLM\Software\WOW6432Node\...\Uninstall\* (éviter Win32_Product en production). Filtrer DisplayName pour « Genian ».Inventaire « Installé / Non installé » par poste avec nom du produit, version, éditeur.
Dépanner les postes non visésVérifier l’OU, le filtrage de sécurité (Authenticated Users ou groupe cible), le WMI filter, l’accès UNC au package MSI, le paramètre « Toujours attendre le réseau… », forcer gpupdate /force et redémarrer si nécessaire.Couverture GPO rétablie et conditions d’installation respectées.
Réinstaller manuellement si besoinScript silencieux msiexec ou EXE avec switches, via Intune, SCCM/ConfigMgr, PDQ, PsExec, tâche planifiée à distance.Installation finalisée sur les postes récalcitrants.

Vérifier l’application de la GPO « Genian NAC »

Avec la console GPMC (cas rapide)

  1. Ouvrez Group Policy Management depuis une machine d’admin avec RSAT.
  2. Clic droit sur Group Policy ResultsRun Wizard.
  3. Sélectionnez l’ordinateur et l’utilisateur (ou « me »/machine locale), exécutez.
  4. Dans le rapport, cherchez la GPO « Genian NAC » : Applied GPOs (appliquée) ou Denied GPOs (refusée), et lisez la raison (sécurité, WMI, héritage, distance de liaison).

En masse avec PowerShell

Si le module GPMC est installé, Get-GPResultantSetOfPolicy peut générer un RSOP au format XML lisible et diffusable :

# Exemple : RSOP pour une machine distante
$computer = "PC-001"
$outXml = "C:\Temp\RSOP_$computer.xml"
Get-GPResultantSetOfPolicy -ReportType Xml -Path $outXml -Computer $computer

# Recherche de la GPO "Genian" dans le RSOP

[xml]$rsop = Get-Content $outXml
$applied = $rsop.Rsop.ComputerResults.GPO | Where-Object { $*.Name -like "*Genian*" -and $*.Applied -eq "true" }
$denied  = $rsop.Rsop.ComputerResults.GPO | Where-Object { $*.Name -like "*Genian*" -and $*.Applied -eq "false" } 

Sans GPMC, utilisez gpresult (XML/HTML) :

gpresult /S PC-001 /SCOPE COMPUTER /H C:\Temp\gpresult_PC-001.html
gpresult /S PC-001 /SCOPE COMPUTER /X C:\Temp\gpresult_PC-001.xml

Collecter les journaux d’installation MSI

Le déploiement par GPO écrit dans le journal Application :

SourceEvent IDSignification
Application Management301 / 302Application de stratégie d’installation logicielle (début/fin, attribution/ publication).
MsiInstaller103–108Résultats de l’installation/suppression/ réparation MSI (message contient souvent « success » ou code d’erreur).
MsiInstaller117–119Résultats liés aux patchs/annonces de produit.

Extraction avec PowerShell (local ou distant) :

$computer = "PC-001"
$events = Get-WinEvent -ComputerName $computer -FilterHashtable @{
  LogName = "Application"
  Id      = 103,104,105,106,107,108,117,118,119,301,302
} -ErrorAction SilentlyContinue |
Where-Object {
  $_.ProviderName -in @("MsiInstaller","Application Management") -and
  $_.Message -match "Genian"
} |
Select-Object TimeCreated, Id, ProviderName, LevelDisplayName, Message

$events | Format-Table -AutoSize 

Export CSV :

$events | Export-Csv C:\Temp\GenianNAC_Events_PC-001.csv -NoTypeInformation -Encoding UTF8

Vérifier la présence réelle du client Genian NAC

Évitez Get-CimInstance Win32_Product en production (lent et peut déclencher des « self-repair »). Préférez la lecture du registre :

function Get-InstalledGenianNac {
  param([string]$ComputerName = $env:COMPUTERNAME)

$paths = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall*",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall*"
)

$script = {
param($paths)
$all = foreach($p in $paths){
if(Test-Path $p){
Get-ItemProperty $p -ErrorAction SilentlyContinue
}
}
$all | Where-Object { $_.DisplayName -like "Genian*" } |
Select-Object PSComputerName, DisplayName, DisplayVersion, Publisher, InstallDate
}

try {
Invoke-Command -ComputerName $ComputerName -ScriptBlock $script -ArgumentList ($paths) -ErrorAction Stop
} catch {
Write-Warning "Impossible d'interroger $ComputerName : $_"
}
}

# Exemple

Get-InstalledGenianNac -ComputerName "PC-001" 

Rapport unifié : qui a (ou n’a pas) reçu Genian NAC

L’idée : pour chaque poste cible, agréger GPO appliquée ?, journaux MSI et présence réelle du produit, puis classifier l’état. Le script ci‑dessous produit à la fois un CSV et un HTML lisibles (style basique intégré).

Script PowerShell clé en main

Pré‑requis : WinRM/PowerShell Remoting activé pour l’interrogation distante, droits d’admin sur les postes, RSAT si vous utilisez Get-GPResultantSetOfPolicy. À défaut, le script bascule vers gpresult.

Param(
  [string]$OU = "",                         # Exemple: "OU=Postes,OU=Paris,DC=contoso,DC=local"
  [string]$ComputerListPath = "",           # Option: CSV avec colonne 'ComputerName'
  [string]$GpoName = "Genian",              # Mot-clé de la GPO/produit
  [string]$OutputFolder = "C:\Temp",        # Où poser CSV/HTML
  [int]$EventLookbackDays = 30
)

# --- Fonctions utilitaires ---------------------------------------------------

function Get-TargetComputers {
if (Test-Path $ComputerListPath) {
Import-Csv $ComputerListPath | ForEach-Object { $*.ComputerName } | Where-Object { $* }
} elseif ($OU) {
if (Get-Module -ListAvailable -Name ActiveDirectory) {
Import-Module ActiveDirectory -ErrorAction Stop
Get-ADComputer -Filter * -SearchBase $OU -SearchScope Subtree |
Select-Object -ExpandProperty Name
} else {
throw "Module ActiveDirectory absent et pas de liste CSV fournie."
}
} else {
throw "Précisez -OU ou -ComputerListPath."
}
}

function Test-Remote {
param([string]$Computer)
Test-Connection -ComputerName $Computer -Count 1 -Quiet -ErrorAction SilentlyContinue
}

function Get-GpoApplied {
param([string]$Computer, [string]$GpoName)

$result = [ordered]@{
Computer      = $Computer
GpoApplied    = $null
GpoReason     = $null
Method        = $null
}

try {
if (Get-Command Get-GPResultantSetOfPolicy -ErrorAction SilentlyContinue) {
$tmp = Join-Path $env:TEMP ("RSOP_{0}.xml" -f $Computer)
Get-GPResultantSetOfPolicy -ReportType Xml -Path $tmp -Computer $Computer -ErrorAction Stop
[xml]$rsop = Get-Content $tmp

```
  $gpos = $rsop.Rsop.ComputerResults.GPO
  if ($gpos) {
    $matchApplied = $gpos | Where-Object { $_.Name -like "*$GpoName*" -and $_.Applied -eq "true" }
    $matchDenied  = $gpos | Where-Object { $_.Name -like "*$GpoName*" -and $_.Applied -ne "true" }
    if ($matchApplied){
      $result.GpoApplied = $true
      $result.GpoReason  = "Applied"
    } elseif ($matchDenied){
      $result.GpoApplied = $false
      $result.GpoReason  = ($matchDenied.Reason -join "; ")
    } else {
      $result.GpoApplied = $false
      $result.GpoReason  = "GPO non trouvée dans RSOP"
    }
  } else {
    $result.GpoApplied = $false
    $result.GpoReason  = "RSOP vide"
  }
  $result.Method = "GPMC"
  Remove-Item $tmp -ErrorAction SilentlyContinue
} else {
  # Fallback gpresult
  $tmp = Join-Path $env:TEMP ("GPRESULT_{0}.xml" -f $Computer)
  cmd /c "gpresult /S $Computer /SCOPE COMPUTER /X `"$tmp`" >nul 2>&1"
  if (Test-Path $tmp) {
    [xml]$xml = Get-Content $tmp
    $names = $xml.Rsop.ComputerResults.GPO | ForEach-Object { $_.Name }
    if ($names -match $GpoName) {
      $result.GpoApplied = $true
      $result.GpoReason  = "Applied (gpresult)"
    } else {
      $result.GpoApplied = $false
      $result.GpoReason  = "Non listée (gpresult)"
    }
    $result.Method = "gpresult"
    Remove-Item $tmp -ErrorAction SilentlyContinue
  } else {
    $result.GpoApplied = $null
    $result.GpoReason  = "gpresult indisponible"
    $result.Method     = "gpresult"
  }
}
```

} catch {
$result.GpoApplied = $null
$result.GpoReason  = "Erreur RSOP/gpresult : $_"
$result.Method     = "error"
}

[pscustomobject]$result
}

function Get-GenianInstallEvidence {
param([string]$Computer, [string]$GpoName, [int]$Days)

$ev = $null
try {
$ev = Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName = "Application"
Id      = 103,104,105,106,107,108,117,118,119,301,302
StartTime = (Get-Date).AddDays(-$Days)
} -ErrorAction Stop | Where-Object {
$*.ProviderName -in @("MsiInstaller","Application Management") -and
$*.Message -match $GpoName
} | Select-Object -First 1 TimeCreated, Id, ProviderName, LevelDisplayName, Message
} catch {
# ignore
}

$reg = $null
try {
$sb = {
param($name)
$paths = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall*",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall*"
)
$items = foreach($p in $paths){ if(Test-Path $p){ Get-ItemProperty $p -ErrorAction SilentlyContinue } }
$items | Where-Object { $_.DisplayName -like "*$name*" } |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
}
$reg = Invoke-Command -ComputerName $Computer -ScriptBlock $sb -ArgumentList $GpoName -ErrorAction Stop
} catch {
# ignore
}

[pscustomobject]@{
Computer       = $Computer
Installed      = [bool]$reg
ProductName    = $reg.DisplayName -join "; "
ProductVersion = $reg.DisplayVersion -join "; "
EventId        = $ev.Id
EventProvider  = $ev.ProviderName
EventTime      = $ev.TimeCreated
EventMessage   = ($ev.Message -replace "\s+"," ").Substring(0, [Math]::Min(400, ($ev.Message -replace "\s+"," ").Length))
}
}

function Classify-Status {
param(
[bool]$Installed,
[nullable[bool]]$GpoApplied,
[int]$EventId,
[string]$EventMessage
)
if ($Installed) { return "Installé" }
if ($GpoApplied -eq $false) { return "GPO non appliquée" }
if ($GpoApplied -eq $true -and $EventId) {
if ($EventId -in 103,302 -and $EventMessage -match "(success|réuss|completed)") {
return "Installé (journaux)"
} else {
return "Échec MSI"
}
}
if ($GpoApplied -eq $true -and -not $EventId) { return "Pas de trace MSI" }
return "Inconnu"
}

# --- Corps principal ---------------------------------------------------------

$start = Get-Date
$computers = Get-TargetComputers | Sort-Object -Unique
Write-Host "Cibles : $($computers.Count) machine(s)"

$results = foreach($c in $computers){
Write-Host "Analyse $c ..."
if (-not (Test-Remote -Computer $c)) {
[pscustomobject]@{
Computer       = $c
Online         = $false
GpoApplied     = $null
GpoReason      = "Hôte injoignable"
Installed      = $false
ProductName    = $null
ProductVersion = $null
EventId        = $null
EventProvider  = $null
EventTime      = $null
EventMessage   = $null
Status         = "Injoignable"
}
continue
}

$gpo = Get-GpoApplied -Computer $c -GpoName $GpoName
$ev  = Get-GenianInstallEvidence -Computer $c -GpoName $GpoName -Days $EventLookbackDays

[pscustomobject]@{
Computer       = $c
Online         = $true
GpoApplied     = $gpo.GpoApplied
GpoReason      = $gpo.GpoReason
Installed      = $ev.Installed
ProductName    = $ev.ProductName
ProductVersion = $ev.ProductVersion
EventId        = $ev.EventId
EventProvider  = $ev.EventProvider
EventTime      = $ev.EventTime
EventMessage   = $ev.EventMessage
Status         = Classify-Status -Installed $ev.Installed -GpoApplied $gpo.GpoApplied -EventId $ev.EventId -EventMessage $ev.EventMessage
}
}

# Export CSV

$csvPath = Join-Path $OutputFolder ("GenianNAC-Rapport_{0:yyyyMMdd_HHmm}.csv" -f $start)
$results | Export-Csv $csvPath -NoTypeInformation -Encoding UTF8

# Export HTML simple

$css = @"

"@

$rows = $results | Select-Object Computer, Online, GpoApplied, GpoReason, Installed, ProductName, ProductVersion, EventId, EventProvider, EventTime, Status

$html = $rows | ConvertTo-Html -Title "Genian NAC - Rapport de déploiement" -Head $css -PreContent "Genian NAC – Rapport de déploiementGénéré le $((Get-Date).ToString()) – Périmètre : $($computers.Count) poste(s)."

$htmlPath = Join-Path $OutputFolder ("GenianNAC-Rapport_{0:yyyyMMdd_HHmm}.html" -f $start)
$html | Set-Content -Path $htmlPath -Encoding UTF8

Write-Host "OK : $csvPath"
Write-Host "OK : $htmlPath" 

Colonnes clés du rapport

  • Computer : nom NetBIOS/FQDN.
  • GpoApplied / GpoReason : verdict d’application de la GPO et raison si refusée.
  • Installed / ProductName / ProductVersion : présence réelle dans le registre.
  • EventId / EventProvider / EventTime : dernière trace MSI pertinente, horodatée.
  • Status : classification finale (Installé, Échec MSI, GPO non appliquée, Pas de trace MSI, Injoignable).

Dépanner les postes non visés

Checklist rapide

  • OU & liaison GPO : l’ordinateur est‑il dans l’OU où la GPO est liée ? L’héritage est‑il bloqué ?
  • Filtrage de sécurité : la GPO est‑elle Appliquée au groupe Authenticated Users (lecture + application) ou à un groupe cible contenant les comptes machines ?
  • WMI filter : la requête correspond‑elle réellement aux machines visées (version d’OS, architecture, niveau de patch) ?
  • Chemin du package : le package MSI/EXE est référencé via un chemin UNC (\\serveur\partage\...), pas un lecteur mappé. Les comptes ordinateurs ont‑ils les droits Lire sur le partage ?
  • Bande passante : si sites distants, envisager DFS-R ou un point de distribution local.
  • Moment de l’installation : pour un déploiement côté Computer Configuration > Software Installation, l’installation se fait au démarrage ; prévoir un ou deux redémarrages.
  • Paramètre réseau : activer « Toujours attendre le réseau lors du démarrage et de l’ouverture de session » afin de ne pas rater le traitement GPO au boot.
  • Services MSI : Windows Installer n’est pas désactivé, l’espace disque est suffisant, et le cache CCMCache/SoftwareDistribution (selon outil) n’est pas corrompu.

Codes et messages d’erreur MSI courants

SymptômePisteAction
ID 103/302 avec « access denied / 0x5 »Partage UNC inaccessible pour le compte ordinateur.Donner « Read » au groupe Domain Computers sur le partage/dossier.
ID 103 avec « another installation is in progress »MSI en conflit.Attendre fin des installations, redémarrer, rejouer GPO.
Échec silencieux, pas d’événement MSIGPO non appliquée ou démarrage trop rapide.Vérifier RSOP, activer « Toujours attendre le réseau », redémarrer 2×.

Réinstaller manuellement sur les postes récalcitrants

Commande silencieuse type

Adaptez au package réel (MSI/EXE) et aux paramètres fournis par l’éditeur.

# MSI silencieux
msiexec /i "\\serveur\logiciels\GenianNAC.msi" /qn /norestart

# EXE (exemple générique)

\serveur\logiciels\GenianNAC_Setup.exe /silent /norestart 

Exécution distante

Quelques options répandues :

  • Intune / SCCM / PDQ : packager l’installeur avec switches silencieux.
  • PsExec : lancer en Local System si besoin d’accès machine.
  • Tâche planifiée : créer à distance une tâche qui exécute l’installation au prochain démarrage.
# Exemple PsExec (exécuté depuis un poste d'admin avec Sysinternals)
psexec \\PC-001 -s -d msiexec /i "\\serveur\logiciels\GenianNAC.msi" /qn /norestart

Bonnes pratiques pour éviter les échecs futurs

  • Hébergement du package : partage hautement disponible, réplication DFS sur sites distants.
  • Versionnement : nommez les GPO et packages avec un indicateur de version (GenianNAC_2.3.1), archivez les anciens MSI.
  • Console serveur Genian : comparez la liste des agents vus par le serveur avec l’inventaire AD pour repérer les postes manquants.
  • Event Forwarding : centralisez les événements MsiInstaller/Application Management pour audit global.
  • Automatisation : exécutez le script d’inventaire en planifié, générez un HTML/CSV pour la DSI.
  • Tests : OU de pré‑prod dédiée, représentative des sites et matériels.

FAQ – Questions fréquentes

Faut‑il redémarrer pour une GPO « Software Installation » côté ordinateur ?
Oui : l’installation se déclenche au démarrage. Après changement de GPO, prévoyez gpupdate /force puis deux redémarrages pour garantir le cycle.

Pourquoi « Win32_Product » est déconseillé ?
Il est lent et peut déclencher des réparations MSI. Préférez la lecture des clés Uninstall dans le Registre (x86 et x64).

Le package s’installe pour certains utilisateurs seulement
Vérifiez si le déploiement a été configuré par utilisateur au lieu de par ordinateur. Selon le cas, l’installation se produit à l’ouverture de session ou au démarrage.

Le package ne se trouve pas
Vérifiez le chemin UNC, les droits NTFS/partage pour les comptes ordinateurs et la résolution DNS/NetBIOS.

Modèle de feuille de route corrective

  1. Exécuter le script pour obtenir le rapport consolidé.
  2. Filtrer sur « GPO non appliquée » : corriger OU/filtrage/WMI, déployer gpupdate.
  3. Filtrer sur « Échec MSI » : lire EventMessage, traiter les causes (droits, verrouillage MSI, disque, dépendances).
  4. Relancer l’installation manuellement sur les machines encore « Non installé ».
  5. Re‑exécuter le script et valider que l’état passe à « Installé ».

Exemple de matrice d’état

GPO appliquéeTrace MSIProduit trouvéStatut finalAction
OuiSuccèsOuiInstalléAucune
OuiÉchecNonÉchec MSIAnalyser EventMessage, relancer installation
NonNonGPO non appliquéeCorriger OU/filtrage/WMI
OuiNonPas de trace MSIVérifier timing au boot, redémarrer
InjoignableCorriger connectivité/pare-feu

Conclusion

En combinant RSOP, journaux MSI et inventaire registre, vous obtenez une image complète du déploiement de Genian NAC. Le script fourni automatise la collecte et la classification, vous permettant d’agir immédiatement : corriger le ciblage GPO, traiter les erreurs MSI et finaliser l’installation sur 100 % du parc.

Sommaire