Compatibilité avec Windows 11 : auditez votre parc informatique avec PowerShell
Sommaire
I. Présentation
Pour de nombreuses entreprises, la migration de Windows 10 à Windows 11 est l'un des projets majeurs de cette année 2025. Cette mise à niveau, qui peut être effectuée grâce à diverses solutions techniques, implique également une phase d'audit. Celle-ci permettra de déterminer quelles sont les machines du parc informatique compatible avec Windows 11, et celles qui ne le sont pas.
Des solutions de gestion de parc ou de gestion d'appareils mobiles, telles que GLPI et Microsoft Intune, peuvent permettre de réaliser cette évaluation grâce à leur fonctionnalité d'inventaire. Pour ceux qui ne sont pas équipés d'une solution adaptée, comment faire ?
Microsoft propose un outil nommé "PC Health Check" mais il doit être exécuté sur chaque poste de travail manuellement, ce qui n'est pas adapté sur un parc informatique de plusieurs dizaines, centaines ou milliers de machines. Dans cet article, je vous propose une approche basée sur l'exécution d'un script PowerShell et la centralisation des résultats dans l'Active Directory.
L'idée est simple : pour chaque machine, indiquer si elle respecte ou non les prérequis de Windows 11, au sein même de l'objet Active Directory correspondant. Un second script sera ensuite exécuté pour générer un rapport d'audit.
II. Utiliser PowerShell pour déterminer la compatibilité avec Windows 11
Le script PowerShell doit vérifier un ensemble d'éléments sur le poste de travail pour déterminer s'il est prêt pour Windows 11 ou non. Il convient notamment de regarder de près les éléments suivants :
- Processeur : 1 GHz ou plus rapide avec au moins 2 cœurs. Processeur compatible 64 bits (ou ARM)
- Mémoire (RAM) : 4 Go ou plus.
- Stockage : 64 Go ou plus.
- Firmware du système : UEFI, compatible avec Secure Boot.
- TPM : version 2.0.
- Carte graphique : compatible avec DirectX 12 ou version ultérieure avec pilote WDDM 2.0.
Microsoft propose un script PowerShell, prêt à l'emploi, que l'on peut exécuter pour savoir si une machine est compatible ou non avec Windows 11. Vous pouvez le télécharger via ce lien :
Vous pouvez l'exécuter sur une machine, en tant qu'administrateur, pour obtenir le résultat. L'avantage de ce script, c'est qu'il indique précisément le résultat de chaque test effectué.
.\HardwareReadiness.ps1
Note : HardwareReadiness.ps1 est un script signé, ce qui explique la présence de la signature à la fin du fichier. Toutefois, elle est expirée puisque le certificat utilisé par Microsoft n'est plus valide depuis septembre 2022.
B. Adaptation du script : centraliser les résultats dans AD
Ce script est une bonne base et il accomplit une bonne partie du travail. L'inconvénient, c'est qu'il retourne un résultat dans la console, ce qui implique d'être devant la machine pour lire le résultat. Ce n'est pas ce que nous voulons.
Remarque : ce script pourrait être exécuté à distance par l'intermédiaire du protocole WinRM. Néanmoins, cela implique que la machine soit en ligne au moment où l'on va l'interroger, et surtout, la Gestion à distance doit être activée sur Windows (ce qui n'est pas le cas par défaut sur Windows 10).
Nous allons modifier ce script PowerShell pour que l'information soit remontée dans l'Active Directory. Par défaut, chaque machine Active Directory dispose de permissions pour modifier les attributs de l'objet correspondant. Nous allons tirer profit de cette opportunité pour venir stocker dans l'Active Directory le résultat du test.
Notre objectif sera le suivant : remonter dans l'attribut info
de chaque objet ordinateur le résultat du script. Nous pourrions choisir un autre attribut, mais celui-ci est généralement libre, contrairement à l'attribut description
qui est très souvent utilisé.
Nous n'allons pas utiliser les commandes du module PowerShell ActiveDirectory pour éviter de devoir l'installer sur les machines distantes. À la place, nous allons utiliser des composants natifs supportés par toutes les machines sous Windows 10.
Commencez par éditer le script PowerShell pour modifier la ligne 490 afin de stocker dans une variable $Result
le résultat du script :
$Result = $outObject | ConvertTo-Json -Compress
Puis, à la suite de la ligne évoquée ci-dessus (mais avant la signature), indiquez ce bout de code :
$ComputerName = $env:COMPUTERNAME
$ADSearch = New-Object DirectoryServices.DirectorySearcher
$ADSearch.SearchRoot = "LDAP://DC=IT-CONNECT,DC=LOCAL"
$ADSearch.Filter = "(&(objectCategory=Computer)(CN=$ComputerName))"
$ADComputerObj = [ADSI]$ADSearch.FindOne().Path
if($ADComputerObj -ne $null){
$ADComputerObj.Put( "Info", $Result )
$ADComputerObj.SetInfo()
}
Voici, dans l'ordre, la signification de ces commandes :
- Récupérer le nom de l'ordinateur local.
- Créer un objet de recherche Active Directory.
- Définir la racine LDAP où chercher.
- Créer un filtre LDAP pour récupérer uniquement l'objet correspondant à l'ordinateur actuel.
- Rechercher l'ordinateur avec une requête LDAP.
- Changer la valeur de l’attribut
Info
de l’ordinateur (si l'ordinateur a bien été trouvé en amont) - Enregistrer la modification dans Active Directory.
Nous allons enregistrer cette nouvelle version sous le nom ADHardwareReadiness.ps1
.
III. Compatibilité Windows 11 : l'analyse à l'échelle d'un parc informatique
A. Exécuter le script PowerShell avec une GPO
Le script PowerShell va être lancé sur les machines à partir d'une stratégie de groupe (GPO). Il sera lancé au démarrage de la machine Windows. Nous allons faire en sorte de cibler uniquement les machines qui exécutent Windows 10, grâce à un filtre WMI. Celles déjà sous Windows 11 n'ont pas intérêt à être intégrées à notre analyse.
À partir de la console de gestion de GPO, créez un nouveau filtre WMI. Grâce à une requête, il va permettre d'appliquer la GPO uniquement aux machines Windows 10, même si l'OU ciblée contient des machines sous Windows 11. Ce sera probablement votre cas... En tout cas, c'est le mien avec l'OU PC
qui sera ciblée (liaison de la GPO).
Indiquez un nom et une description (1), puis cliquez sur le bouton "Ajouter" (2). Indiquez ceci comme valeur de requête WMI (3), puis validez (4) :
SELECT * FROM Win32_OperatingSystem WHERE Version LIKE "10.%" AND ProductType = 1
Validez. Créez une nouvelle GPO et commencez par lui associer le filtre WMI créé précédemment.
Ensuite, éditez la stratégie de groupe pour la configurer. Pour rappel, le script PowerShell doit être lancé au démarrage de la machine. Parcourez les paramètres de cette façon :
- Configuration ordinateur > Stratégies > Paramètres Windows > Scripts (démarrage/arrêt) > Démarrage
Basculez sur l'onglet "PowerShell" et cliquez sur le bouton "Ajouter".
Vous devez alors copier-coller votre script PowerShell dans le répertoire exposé ou aller le chercher s'il est ailleurs (dans Netlogon, par exemple).
Voilà, votre GPO est prête ! Vous n'avez plus qu'à la lier sur une ou plusieurs OU selon vos besoins (pensez à tester avant !). Rendez-vous sur une machine Windows 10 pour effectuer un test : exécutez un gpupdate /force
puis redémarrez. La suite se passe dans l'AD...
B. Aperçu des résultats dans l'Active Directory
Nous allons commencer par un contrôle visuel. Ouvrez la console Utilisateurs et ordinateurs Active Directory, puis accédez aux propriétés de l'objet ordinateur correspond à la machine de test (pensez à activer l'affichage des fonctionnalités avancées en amont).
Accédez à l'onglet nommé "Éditeur d'attributs". Après, recherchez l'attribut info
dans la liste. L'attribut a été mis à jour !
Concrètement, nous avons dans cet attribut une chaine complète sous cette forme :
{"returnCode":1,"returnReason":"Storage, TPM, ","logging":"Storage: OSDiskSize=63GB. FAIL; Memory: System_Memory=4GB. PASS; TPM: TPMVersion=False. FAIL; Processor: {AddressWidth=64; MaxClockSpeed=3992; NumberOfLogicalCores=2; Manufacturer=AuthenticAMD; Caption=AMD64 Family 25 Model 117 Stepping 2; }. PASS; SecureBoot: Capable. PASS; ","returnResult":"NOT CAPABLE"}
Nous pourrions exécuter la commande ci-dessous pour afficher le nom et le résultat du test pour chaque machine sous Windows 10 inscrite dans l'AD.
Get-ADComputer -Filter {OperatingSystem -like "Windows 10*"} -Property OperatingSystem, Info | Format-Table Name, Info
Le format de la chaine présente dans l'attribut info
va peut-être vous évoquer quelque chose ? Non, vous ne trouvez pas ? Le format JSON ! Cela s'explique par l'utilisation du cmdlet ConvertTo-Json
à la fin du script. La bonne nouvelle, c'est que PowerShell sait très bien lire du JSON. C'est ce que nous allons exploiter dans la prochaine partie de cet article dédiée au reporting.
C. La compatibilité avec le SecureBoot
En effectuant plusieurs tests avec ce script, je me suis rendu compte que la compatibilité avec le SecureBoot, ne remontait pas toujours correctement. En effet, la commande PowerShell Confirm-SecureBootUEFI
ne semble pas apprécier l'exécution en tant que SYSTEM
via une GPO.
Résultat, nous obtenons ce type de résultat dans AD :
{"returnCode":-1,"returnReason":"","logging":"Storage: OSDiskSize=126GB. PASS; Memory: System_Memory=4GB. PASS; TPM: TPMVersion=2.0, 0, 1.16. PASS; Processor: {AddressWidth=64; MaxClockSpeed=3992; NumberOfLogicalCores=2; Manufacturer=AuthenticAMD; Caption=AMD64 Family 25 Model 117 Stepping 2; }. PASS; SecureBoot: Undetermined. UNDETERMINED; UnauthorizedAccessException Impossible de définir les privilèges nécessaires. Accès refusé.; ","returnResult":"UNDETERMINED"}
C'est dommage, car cette commande présente l'avantage de retourner un état précis : SecureBoot disponible et activé, SecureBoot disponible et désactivé, et SecureBoot non pris en charge. Pour contourner ce problème, le script ADHardwareReadiness.ps1
a été modifié afin d'adapter le test lié au SecureBoot, en passant sur une méthode basée sur le Registre Windows (à partir de la ligne 431).
Le code suivant a été intégré, à la place de celui d'origine (lien de téléchargement en bas de page) :
# SecureBoot
$SecureBootKey = "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State"
try {
$isSecureBootEnabled = (Get-ItemProperty -Path $SecureBootKey -Name "UEFISecureBootEnabled" -ErrorAction Stop).UEFISecureBootEnabled
if($isSecureBootEnabled -eq 1){
$outObject.logging += $logFormatWithBlob -f $SECUREBOOT_STRING, $CAPABLE_STRING, $PASS_STRING
UpdateReturnCode -ReturnCode 0
}else{
UpdateReturnCode -ReturnCode 1
$outObject.returnReason += $logFormatReturnReason -f $SECUREBOOT_STRING
$outObject.logging += $logFormatWithBlob -f $SECUREBOOT_STRING, $NOT_CAPABLE_STRING, $FAIL_STRING
$exitCode = 1
}
}
catch {
UpdateReturnCode -ReturnCode -1
$outObject.logging += $logFormatWithBlob -f $SECUREBOOT_STRING, $UNDETERMINED_STRING, $UNDETERMINED_CAPS_STRING
$outObject.logging += $logFormatException -f "$($_.Exception.GetType().Name) $($_.Exception.Message)"
$exitCode = 1
}
Suite à cette modification, les informations remontent correctement ! Désormais, nous allons pouvoir évoquer la phase de reporting.
Remarque : l'exécution de la commande
Confirm-SecureBootUEFI
au travers de PsExec fonctionne, ce qui peut représenter une piste à explorer, mais implique d'exécuter cet outil sur les postes à auditer.
D. Création d'un rapport
Pour terminer, nous allons, toujours à l'aide de PowerShell, lire les informations contenues dans l'attribut info
des machines Windows 10 pour générer un rapport complet. Très rapidement, vous pouvez :
- Voir le pourcentage de votre parc qui est compatible avec Windows 11
- Voir les principales raisons lorsqu'une incompatibilité est détectée
- Obtenir un état précis pour chaque ordinateur grâce au tableau récapitulatif
Ci-dessous, un aperçu de ce rapport.
Ce script, que vous pouvez retrouver sur notre GitHub, s'appuie sur le module PSWriteHtml pour générer le rapport HTML. Vous pouvez le modifier selon vos besoins.
<#
.SYNOPSIS
This script analyzes the “info” attribute of Windows 10 computers in the Active Directory, to generate a Windows 11 compatibility report.
.DESCRIPTION
This script helps you get an overall view of the Windows 11 compatibility of a set of computers, thanks to an HTML report comprising several graphs.
.AUTHOR
Florian Burnel - IT-Connect.fr
.VERSION
1.0 - Initial version.
.NOTES
Filename: Get-ADHardwareReadinessReport.ps1
Creation Date: 2025/02/18
#>
# Get a list of Windows 10 computers in the Active Directory
$ADComputersWin10 = Get-ADComputer -Filter {OperatingSystem -like "Windows 10*"} -Property OperatingSystem, Info | Sort-Object Name
# Get the list of Windows 10 computers and the result of the compatibility test
$ComputersW11Readiness = $ADComputersWin10 | Select-Object Name, @{
Name="Result";
Expression={
$JsonObject = $_.Info | ConvertFrom-Json
if ($JsonObject.returnResult -ne $null){ $JsonObject.returnResult }else{ "EMPTY" }
}
}, @{
Name="Reason";
Expression={
$JsonObject = $_.Info | ConvertFrom-Json
if($JsonObject.returnReason -ne $null){ ($JsonObject.returnReason).TrimEnd(", ") }else{ "" }
}
}
# Counting by status
$ComputersW11ReadinessStats = $ComputersW11Readiness | Group-Object -Property Result | Sort-Object Count -Descending
# Counting occurrences of different reasons
$ReasonCounts = @{}
$ComputersW11Readiness | ForEach-Object {
$Reasons = $_.Reason -split ", "
foreach ($Reason in $Reasons) {
if (-not [string]::IsNullOrWhiteSpace($Reason)) {
if ($ReasonCounts.ContainsKey($Reason)) {
$ReasonCounts[$Reason]++
} else {
$ReasonCounts[$Reason] = 1
}
}
}
}
# HTML report construction with PSWriteHTML
New-HTML -Title "Compatibility of computers with Windows 11" -FilePath "C:\Scripts\HTML\Rapport-Windows-11-Readiness.html" -ShowHTML:$true {
# Report header with domain name and date
New-HTMLHeader {
New-HTMLSection -Invisible {
New-HTMLPanel -Invisible {
New-HTMLText -Text "Domain : $($env:USERDNSDOMAIN)" -FontSize 18 -FontWeight 100
New-HTMLText -Text "Date : $(Get-Date -Format "dd/MM/yyyy")" -FontSize 12
} -AlignContentText left
}
}
# Section 1 - Graphs
New-HTMLSection -HeaderText "Compatibility with Windows 11" -HeaderBackGroundColor "#00698e" {
New-HTMLChart -Title "Compatibility of all IT assets" -Gradient {
foreach ($Line in $ComputersW11ReadinessStats) {
New-ChartDonut -Name $Line.Name -Value $Line.Count
}
}
New-HTMLChart -Title "Reasons for incompatibility" -Gradient {
foreach ($Reason in $ReasonCounts.Keys) {
New-ChartDonut -Name $Reason -Value $ReasonCounts[$Reason]
}
}
}
# Section 2 - Computer list tables
New-HTMLSection -HeaderText "Results of computer compatibility tests" -HeaderBackGroundColor "#00698e" {
New-HTMLPanel {
New-HTMLTable -DataTable $ComputersW11Readiness -HideFooter -AutoSize
}
}
}
IV. Conclusion
Grâce à ces deux scripts, vous disposez d'une méthode simple et efficace pour évaluer la compatibilité de votre parc informatique avec Windows 11. En s'appuyant sur un domaine Active Directory, cette approche permet d'automatiser l'audit des machines et de vérifier rapidement si elles répondent aux critères requis, notamment le TPM (un point de blocage important dans de nombreux cas).
Que ce soit pour une mise à jour planifiée ou une migration progressive, ces scripts vous offrent une vision claire de l'état de vos postes. Ils vous aident ainsi à préparer votre projet de migration vers Windows 11.
Voici les liens pour télécharger les scripts.
- ADHardwareReadiness.ps1 - À exécuter par GPO
- Get-ADHardwareReadinessReport.ps1 - Pour générer le rapport
Si vous avez des questions ou des idées d'amélioration de ces scripts, n'hésitez pas à commenter cet article ou à pousser une modification sur le GitHub.
Bonjour Florian,
Bravo pour le site et les articles de qualité.
Je tiens à ajouter une précision sur cet article de compatibilité W11, notamment la partie stockage. En effet, j’utilise déjà ce script pour mon client dans la cadre de la migration W11.
La partie qui vérifie le stockage se contente de vérifier que le disque dur est supérieur à 64Go. Donc, par exemple, un poste qui possède un disque dur de 250Go mais qui aura 5Go d’espace libre aura comme résultat final « Capable », ce qui pose problème lors de l’upgrade. J’ai donc dû modifier ce script pour prendre en compte l’espace libre de la machine ce qui rend les informations plus précises sur l’état du poste (et éviter d’avoir des messages des différentes régions qui me disent « ça marche pas!! »)
Voilà, bon courage pour la suite,
Nicolas
Bonjour Nicolas,
Excellente remarque, effectivement, cela apporterait plus de précisions au script ! Je vais voir pour le faire évoluer (ou si tu veux pousser une modif via le GitHub pour participer).
Bonjour,
J’ai testé la manipulation tout fonctionne.
Par contre même avec le script modifié à la ligne 431 j’ai toujours l’erreur d’autorisation concernant le secure boot.
Bonjour,
Existe-il une version adaptée pour un parc en full Azure ?
Cordialement
Bonjour Florian,
Bravo et Merci pour ce site et ses merveilleux tutos. Par contre j’ai testé cette méthode mais je me retriuve avec ce message d’erreur suivant lorsque j’exécute le script pour générer le rapport :
New-HTML : Le terme « New-HTML » n’est pas reconnu comme nom d’applet de commande, fonction, fichier de script ou programme exécutable. Vérifiez l’orthographe du nom, ou si un chemin d’accès existe, vérifiez que le chemin d’accès est correct et réessayez.
Au caractère Ligne:59 : 1
+ New-HTML -Title « Compatibility of computers with Windows 11 » -FilePat …
+ ~~~~~~~~
+ CategoryInfo : ObjectNotFound: (New-HTML:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Bonjour,
Il doit manquer le module PSWriteHtml sur votre machine.
Install-Module -Name PSWriteHtml