PowerShell sur trois plateformes : ce que ça change concrètement
Jusqu’à PowerShell 5.1, la question du système d’exploitation courant n’avait pas vraiment lieu d’être posée depuis un script : PowerShell était Windows, point final. Depuis la version 6.0, publiée en 2018 sous le nom PowerShell Core, tout a changé. Microsoft a rendu l’outil open source et l’a porté sur Linux et macOS, créant une situation que les administrateurs système n’avaient jamais eu à gérer avant : un même fichier .ps1 peut s’exécuter sur trois environnements radicalement différents.
Les versions actuelles de PowerShell — 7.5 en branche stable et 7.6 en LTS — sont disponibles nativement sur Ubuntu, Debian, Fedora, macOS 12 et supérieur, et bien sûr Windows 10/11. Un script d’automatisation partagé entre équipes peut donc atterrir sur n’importe quelle de ces cibles. Dès qu’un chemin de fichier, une commande système ou une variable d’environnement diffère selon l’OS, le script doit savoir où il tourne.
Cette détection n’est pas un détail de confort. Sur Linux, /etc/hosts existe là où Windows attend C:\Windows\System32\drivers\etc\hosts. La commande pour lister les processus, créer un lien symbolique ou vider le cache DNS diffère d’un OS à l’autre. Sans détection fiable, un script « multiplateforme » reste un script qui casse en dehors de sa machine d’origine.
$IsWindows, $IsLinux, $IsMacOS : les variables qui font le travail
PowerShell 6 et versions ultérieures exposent trois variables booléennes automatiques : $IsWindows, $IsLinux et $IsMacOS. Chacune vaut $true sur la plateforme correspondante et $false sur les deux autres. Elles sont définies au démarrage de la session, sans qu’aucune importation de module soit nécessaire.
La syntaxe est directe :
if ($IsWindows) {
Write-Host "Windows détecté"
} elseif ($IsLinux) {
Write-Host "Linux détecté"
} elseif ($IsMacOS) {
Write-Host "macOS détecté"
} else {
Write-Host "Plateforme inconnue"
}
La casse n’a pas d’importance dans PowerShell : $iswindows, $IsWindows ou $ISWINDOWS sont équivalents. La convention habituelle est d’adopter la forme PascalCase visible dans la documentation officielle Microsoft.
Ces variables couvrent les cas les plus courants dans un bloc conditionnel simple. Pour des scripts plus structurés, elles s’utilisent aussi dans des instructions switch ou comme valeurs passées à des fonctions.
Le cas de Windows PowerShell 5.1 : quand ces variables n’existent pas
Windows PowerShell 5.1 est toujours préinstallé sur Windows 10 et Windows 11. C’est souvent la version lancée par défaut quand un utilisateur tape powershell dans un terminal. Sur cette version, $IsWindows, $IsLinux et $IsMacOS sont simplement indéfinies : elles retournent $null, ce qui rend tout bloc conditionnel basé dessus silencieusement incorrect.
Deux alternatives permettent de s’en sortir :
$PSVersionTable.PSEdition: vaut"Desktop"sous Windows PowerShell 5.1, et"Core"sous PowerShell 6+. Ce n’est pas une détection d’OS directe, mais c’est suffisant pour savoir qu’on est sur un environnement Windows-only.[Environment]::OSVersion.Platform: retourne une valeur de l’énumération .NETPlatformID. Sous Windows, la valeur estWin32NT. Cette propriété est disponible même en PowerShell 5.1.
Un bloc de compatibilité rétroactive peut ressembler à ceci :
if ($null -ne $IsWindows) {
# PowerShell 6+ : on utilise les variables natives
$estWindows = $IsWindows
} else {
# Fallback pour Windows PowerShell 5.1
$estWindows = ([Environment]::OSVersion.Platform -eq 'Win32NT')
}
Cette approche évite de planter sur 5.1 tout en tirant parti des variables natives dès que la version le permet. Les environnements où un outil n’est pas reconnu comme attendu à cause de la version du moteur d’exécution suivent souvent la même logique de détection préalable.
Lire $PSVersionTable pour aller plus loin que le simple nom de l’OS
$PSVersionTable est une table de hachage disponible dans toutes les versions de PowerShell. Elle expose plusieurs propriétés utiles au-delà du simple nom du système :
PSVersion: la version exacte de PowerShell sous forme d’objet (Major,Minor,Patch).PSEdition:"Core"ou"Desktop".OS: une chaîne lisible décrivant le système sous-jacent, par exemple"Linux 5.15.0-1045-azure #50-Ubuntu SMP"ou"Darwin 23.4.0 Darwin Kernel..."sur macOS.Platform: retourne"Unix"sur Linux et macOS,"Win32NT"sur Windows.
Cette table devient utile dès qu’un script dépend à la fois de la plateforme et d’une version minimale de PowerShell. Par exemple, certaines API n’existent qu’à partir de PowerShell 7.2, quelle que soit la plateforme. Vérifier $PSVersionTable.PSVersion.Major -ge 7 avant d’appeler ces fonctionnalités évite une erreur peu explicite à l’exécution.
La propriété OS permet aussi de distinguer des variantes Linux si le besoin s’en fait sentir, en parsant la chaîne retournée — bien que cette pratique soit moins robuste que les variables booléennes natives pour une détection de haut niveau.
Écrire un script qui s’adapte à l’OS sans se répéter
La tentation courante est d’insérer des blocs if ($IsWindows) partout dans le script, au fil des besoins. Le résultat devient vite difficile à lire et encore plus difficile à maintenir. Une structure plus propre consiste à centraliser la détection en début de script et à définir des variables ou des fonctions qui absorbent les différences.
Exemple concret : un script qui doit trouver le répertoire temporaire et vider son contenu :
# Détection unique en début de script
if ($IsWindows -or $null -eq $IsWindows) {
$tempDir = $env:TEMP
$clearCmd = { Remove-Item "$tempDir\*" -Recurse -Force -ErrorAction SilentlyContinue }
} elseif ($IsLinux) {
$tempDir = "/tmp"
$clearCmd = { Remove-Item "$tempDir/*" -Recurse -Force -ErrorAction SilentlyContinue }
} elseif ($IsMacOS) {
$tempDir = $env:TMPDIR
$clearCmd = { Remove-Item "$tempDir*" -Recurse -Force -ErrorAction SilentlyContinue }
}
Write-Host "Répertoire temporaire : $tempDir"
& $clearCmd
Write-Host "Nettoyage terminé."
Ce schéma — détecter une fois, abstraire dans des variables, consommer sans condition — évite la duplication et garde la logique métier du script séparée des particularités de chaque OS. Si un quatrième cas apparaît (une distribution Linux avec un /tmp monté différemment, par exemple), il suffit d’ajuster le bloc d’initialisation sans toucher au reste.
Quand un script de ce type est partagé dans une équipe mixte — certains sur Windows, d’autres sur Linux — les erreurs liées à des chemins codés en dur ou à des restrictions d’accès héritées de la configuration système disparaissent pour la plupart dès que la détection d’OS est correctement implémentée. C’est aussi ce qui permet à un script de CI/CD de tourner identiquement sur un agent Windows et un agent Linux sans duplication de code dans la pipeline.