Introduction
La mise à niveau de PowerShell fait partie des changements à plus fort levier pour votre automatisation Windows et multiplateforme. PowerShell 7 apporte un runtime moderne, de meilleures performances et une maintenabilité à long terme tout en conservant une syntaxe et des outils familiers. La méthode la plus sûre consiste en une installation côte à côte avec Windows PowerShell 5.1, une validation minutieuse des modules et scripts, et un plan de retour arrière exécutable en quelques minutes.
Ce guide praticien se concentre sur :
- Inventaire : versions, modules, scripts, profils, tâches planifiées et stratégies.
- Une trajectoire de migration sûre : installation côte à côte et pilotes restreints et observables.
- Vérification : commandes, résultats attendus et diagnostics.
- Modes de défaillance et récupération : retours arrière prévisibles et vérifications de confirmation.
- Une liste de contrôle reproductible pour les équipes.
Un pilote étroit et mesurable, que vous pouvez inspecter localement avant déploiement, est le moyen le plus rapide de réduire les risques et de gagner en confiance pour un déploiement plus large.
Inventaire des versions et de l'environnement
Connaître l'existant avant de le modifier. Capturez la référence une fois, stockez-la avec votre documentation d'infrastructure, et réutilisez-la pour les audits futurs.
1) Version et hôte principaux
Exécutez ce qui suit dans chaque environnement concerné :
# Détails version et hôte
$PSVersionTable
Get-Host | Select-Object Name, Version
# Architecture et plateforme OS
[Environment]::Is64BitOperatingSystem
Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture
Résultat attendu : vous voyez clairement si vous êtes sur Windows PowerShell 5.1 (powershell.exe) ou PowerShell 7+ (pwsh.exe), ainsi que la version et l'architecture de l'OS.
2) Inventaire des modules et chemins
# Lister les modules installés et leurs versions
Get-Module -ListAvailable | Sort-Object Name, Version | Select-Object Name, Version, Path
# Où PowerShell cherche les modules
($env:PSModulePath -split ';') | ForEach-Object { $_.Trim() }
Notez les modules critiques qui sont Windows uniquement ou qui dépendent d'API .NET Framework.
3) Scripts, tâches planifiées et services
Identifiez les scripts susceptibles d'être affectés par le changement d'hôte (powershell.exe vers pwsh.exe) :
# Inventaire des scripts dans un dépôt ou racine de système de fichiers
$root = 'C:\Automation' # chemin d'exemple construit
Get-ChildItem -Path $root -Recurse -Filter *.ps1 | Select-Object FullName
Trouvez les tâches planifiées qui appellent powershell.exe :
Get-ScheduledTask |
Where-Object { $_.Actions.Execute -match 'powershell.exe' } |
Select-Object TaskName, TaskPath, @{n='Action';e={$_.Actions.Execute}}, @{n='Args';e={$_.Actions.Arguments}}
Enregistrez les services ou scripts démarrés par des services Windows qui intègrent un chemin vers powershell.exe.
4) Stratégie d'exécution et profils
# Stratégie d'exécution selon les portées
Get-ExecutionPolicy -List
# Fichiers de profil selon les hôtes
$profiles = [pscustomobject]@{
CurrentUserAllHosts = $PROFILE.CurrentUserAllHosts
CurrentUserCurrentHost = $PROFILE.CurrentUserCurrentHost
AllUsersAllHosts = $PROFILE.AllUsersAllHosts
AllUsersCurrentHost = $PROFILE.AllUsersCurrentHost
}
$profiles
$profiles.PSObject.Properties | ForEach-Object {
$_.Name, (Resolve-Path $_.Value -ErrorAction SilentlyContinue) -join ': '
}
Résultat attendu : vous disposez d'une liste des scripts de profil à préserver et d'une vision claire des stratégies d'exécution.
Aide-mémoire d'inventaire
- Version du moteur :
$PSVersionTable— notez l'édition et la version PS (5.1 vs 7.x). - Modules :
Get-Module -ListAvailable— notez les noms et versions des modules critiques. - Chemins des modules :
$env:PSModulePath -split ';'— distinguez les répertoires utilisateur et système. - Scripts :
Get-ChildItem -Recurse *.ps1— listez les scripts critiques et leurs propriétaires. - Tâches planifiées :
Get-ScheduledTask | Where-Object { $_.Actions.Execute -match 'powershell.exe' }— capturez noms de tâches et arguments. - Profils : variantes
$PROFILE— enregistrez les chemins à migrer ou préserver.
Trajectoire de configuration sûre
L'approche la plus sûre est l'installation côte à côte de PowerShell 7 tout en conservant Windows PowerShell 5.1. Cela permet de tester sans casser les travaux existants.
1) Installer côte à côte
Sous Windows, utilisez un gestionnaire de paquets ou le MSI. Les deux placent pwsh.exe généralement sous C:\Program Files\PowerShell\7\pwsh.exe.
# Option A : winget (nécessite winget disponible)
winget install --id Microsoft.PowerShell -e
# Option B : Chocolatey (si utilisé en interne)
choco install powershell -y
Vérification :
# Confirmer l'installation
"powershell.exe" -NoProfile -Command "$PSVersionTable.PSVersion.ToString()"
"pwsh.exe" -NoProfile -Command "$PSVersionTable.PSVersion.ToString()"
Résultat attendu : les deux hôtes s'exécutent et rapportent leurs versions.
2) Pilote d'abord
Commencez par un pilote restreint et mesurable, facile à inspecter localement avant déploiement. Bons candidats :
- Un script utilitaire exécuté fréquemment qui lit une entrée et produit du texte ou du JSON.
- Une tâche planifiée avec une sortie bien définie et observable (dépôt de fichier, entrée de journal, ou événement).
- Un module qui dispose de tests unitaires ou d'un comportement déterministe.
Exemple de pilote construit :
- Périmètre : un script d'export de données qui écrit
C:\Automation\out\daily.json. - Observable : le fichier existe, le JSON est valide, et le nombre de lignes correspond à hier +/- 2 % (seuil hypothétique).
- Métrique de succès : 7 exécutions consécutives réussies sous PowerShell 7.
Exemples de candidats pilotes :
- Script utilitaire : un script d'export → fichier JSON valide avec nombre de lignes stable.
- Tâche planifiée : tâche unique avec sortie fichier → fichier daté apparaît avec taille attendue.
- Module : une applet de commande de module interne → fonction déterministe retourne la même sortie.
3) Profils et paramètres
Gardez les profils séparés jusqu'à validation. Copiez ensuite intentionnellement.
# Identifier les chemins de profil 5.1 et 7 (exemple construit)
$ps51 = Join-Path $HOME 'Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1'
$ps7 = Join-Path $HOME 'Documents\PowerShell\Microsoft.PowerShell_profile.ps1'
# Sauvegarder et copier sélectivement les lignes de confiance
if (Test-Path $ps51) { Copy-Item $ps51 "$ps51.bak" -Force }
New-Item -ItemType Directory -Force -Path (Split-Path $ps7) | Out-Null
if (-not (Test-Path $ps7)) { New-Item -ItemType File -Path $ps7 | Out-Null }
# Exemple : ajouter des alias/fonctions sûrs seulement après test
Add-Content $ps7 '# Aliases migrés après validation'
4) Compatibilité des modules
De nombreux modules fonctionnent tel quel sur PowerShell 7. Les modules Windows uniquement peuvent nécessiter le shim de compatibilité Windows PowerShell :
# Tenter un import normal d'abord
Import-Module SomeWindowsOnlyModule -ErrorAction Stop
# Si échec dans 7, charger via la compatibilité Windows PowerShell
Import-Module SomeWindowsOnlyModule -UseWindowsPowerShell -Verbose
Résultat attendu : le module se charge avec succès ou vous avez une erreur claire à investiguer. Utilisez -Verbose pour voir les détails de chargement.
5) Basculer les tâches planifiées progressivement
Ne basculez une tâche de powershell.exe vers pwsh.exe qu'après la réussite du pilote.
# Aperçu des tâches à modifier
Get-ScheduledTask |
Where-Object { $_.Actions.Execute -match 'powershell.exe' } |
Select-Object TaskName, @{n='Args';e={$_.Actions.Arguments}}
# Exemple construit de mise à jour du chemin et arguments d'une action de tâche
$taskName = 'DailyExport' # exemple construit
$task = Get-ScheduledTask -TaskName $taskName
$action = New-ScheduledTaskAction -Execute 'C:\Program Files\PowerShell\7\pwsh.exe' -Argument $task.Actions.Arguments
Set-ScheduledTask -TaskName $taskName -Action $action
Vérification :
# Déclencher manuellement hors heures
Start-ScheduledTask -TaskName 'DailyExport'
Start-Sleep -Seconds 10
Get-ScheduledTaskInfo -TaskName 'DailyExport'
Résultat attendu : la tâche s'exécute, et sa sortie observable apparaît comme prévu.
Vérification et diagnostics
Votre but : rendre le succès évident et l'échec bruyant.
1) Vérifications d'hôte et de chemin
# Confirmer le chemin pwsh sous Windows
$pwshPath = (Get-Command pwsh).Source
$pwshPath
Test-Path $pwshPath
# Confirmer que le PATH Machine contient PowerShell 7
[Environment]::GetEnvironmentVariable('Path','Machine') -split ';' | Where-Object { $_ -match 'PowerShell\\7' }
Résultat attendu : pwsh se résout correctement et figure dans le PATH.
2) Stratégie d'exécution dans PowerShell 7
Les stratégies peuvent différer selon l'hôte. Vérifiez dans 5.1 et 7.
# Dans pwsh
Get-ExecutionPolicy -List
# Si nécessaire, définir pour l'utilisateur courant dans 7
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
Résultat attendu : la stratégie est compatible avec vos scripts et exigences de sécurité.
3) Test de parité de sortie entre 5.1 et 7
Utilisez un script déterministe et comparez les sorties.
# Exemple construit
$script = 'C:\Automation\Export-Data.ps1'
"powershell.exe" -NoProfile -File $script -OutFile C:\Temp\out-51.json
"pwsh.exe" -NoProfile -File $script -OutFile C:\Temp\out-7.json
# Comparer par taille et clés JSON (heuristique simple)
$size51 = (Get-Item C:\Temp\out-51.json).Length
$size7 = (Get-Item C:\Temp\out-7.json).Length
[math]::Round((($size7 - $size51) / [double]$size51) * 100, 2)
# Vérification ponctuelle de la structure JSON si applicable
$one51 = Get-Content C:\Temp\out-51.json -Raw | ConvertFrom-Json | Select-Object -First 1
$one7 = Get-Content C:\Temp\out-7.json -Raw | ConvertFrom-Json | Select-Object -First 1
$one51.PSObject.Properties.Name | Sort-Object
$one7.PSObject.Properties.Name | Sort-Object
Résultat attendu : les sorties sont identiques ou dans une tolérance acceptable pour votre cas d'usage.
4) Journalisation et diagnostics
# Créer une transcription d'exécution pour une exécution
$logDir = 'C:\Logs'
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
$ts = Join-Path $logDir ("pwsh-run-" + (Get-Date -Format yyyyMMdd_HHmmss) + \).log\)
Start-Transcript -Path $ts
# Votre script
& pwsh -NoProfile -File 'C:\Automation\Export-Data.ps1' -Verbose
Stop-Transcript
Résultat attendu : un journal clair que vous pouvez joindre aux dossiers d'incident ou revues de changement.
5) Tests de chargement des modules
# Tester programmatiquement une liste de modules critiques dans pwsh
$modules = 'Az.Accounts','SqlServer','ActiveDirectory' # exemples construits
foreach ($m in $modules) {
try {
Import-Module $m -ErrorAction Stop -Verbose:($VerbosePreference -eq 'Continue')
Write-Host "OK: $m"
} catch {
Write-Warning "FAIL: $m -> $($_.Exception.Message)"
}
}
Résultat attendu : vous avez un rapport simple de réussite/échec pour les modules critiques.
Modes de défaillance et récupération
Les problèmes suivants sont courants et faciles à anticiper.
- Incompatibilité de module :
Import-Moduleéchoue danspwsh→ utilisez-UseWindowsPowerShellou conservez l'hôte 5.1 pour ce script. - Confusion PATH :
pwshintrouvable ou mauvaise version → utilisez le chemin completC:\Program Files\PowerShell\7\pwsh.exeet vérifiez le PATH. - Blocage par stratégie d'exécution : le script ne s'exécute pas dans
pwsh→ alignez la stratégie avecSet-ExecutionPolicy -Scope CurrentUser. - Erreurs de profil :
pwshdémarre avec des erreurs rouges → mettez en commentaire les lignes non portables et migrez sélectivement. - Tâche planifiée ne démarre pas : l'action pointe encore vers
powershell.exe→ mettez à jour l'action verspwsh.exeseulement après validation.
Plan de retour arrière
Visez à inverser les changements en minutes, pas en heures.
- Conservez Windows PowerShell 5.1 disponible.
- Restaurez les tâches planifiées vers
powershell.exesi le basculement échoue :
$taskName = 'DailyExport' # exemple construit
$task = Get-ScheduledTask -TaskName $taskName
$action = New-ScheduledTaskAction -Execute 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -Argument $task.Actions.Arguments
Set-ScheduledTask -TaskName $taskName -Action $action
- Restaurez les profils depuis la sauvegarde :
Copy-Item "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1.bak" `"$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" -Force
- Si nécessaire, supprimez PowerShell 7 tout en conservant 5.1 :
# Désinstaller via winget (exemple construit ; confirmer l'ID de paquet d'abord)
winget uninstall --id Microsoft.PowerShell -e
- Validez la récupération :
"powershell.exe" -NoProfile -Command "$PSVersionTable.PSVersion.ToString()"
Get-ScheduledTask | Where-Object { $_.Actions.Execute -match 'powershell.exe' } | Select-Object TaskName
Test-Path 'C:\Program Files\PowerShell\7\pwsh.exe' # devrait être False si désinstallé
Résultat attendu : les travaux principaux tournent à nouveau sous 5.1, et l'environnement est stable.
Liste de contrôle opérationnelle
Utilisez cette liste concise pour chaque environnement.
Planification
- Définir la raison métier et les critères de réussite de la mise à niveau.
- Choisir un pilote restreint et mesurable que vous pouvez vérifier localement.
Inventaire
- Enregistrer versions du moteur, OS, architecture.
- Exporter la liste des modules et versions critiques.
- Lister scripts, tâches planifiées et services appelant
powershell.exe. - Capturer stratégies d'exécution et chemins de profil.
Pilote
- Installer PowerShell 7 côte à côte.
- Exécuter le script pilote dans les deux hôtes ; comparer les sorties.
- Tester les imports de modules ; ajouter
-UseWindowsPowerShellsi nécessaire. - Configurer la stratégie d'exécution pour CurrentUser si requis.
- Instrumenter avec
-Verbose, transcriptions et journaux clairs.
Basculement (pilote seulement)
- Mettre à jour une tâche planifiée pour utiliser
pwsh.exe. - Déclencher manuellement ; vérifier les sorties observables.
- Surveiller pendant 7 exécutions consécutives réussies (cible construite).
Déploiement plus large
- Traiter plus de scripts/tâches par petits lots.
- Garder les étapes de retour arrière prêtes pour chaque lot.
- Mettre à jour la documentation : matrice des versions, exceptions connues, et propriétaires.
Retour arrière (si nécessaire)
- Revenir aux tâches vers
powershell.exe. - Restaurer les sauvegardes de profils et configuration.
- Désinstaller PowerShell 7 si souhaité.
- Confirmer la stabilité et consigner les leçons apprises.
Conclusion
Une mise à niveau PowerShell prudente, côte à côte, est simple quand on commence petit, mesure clairement, et maintient un retour arrière rapide. Débutez par un pilote facile à inspecter localement, prouvez la parité de sortie, puis étendez par lots contrôlés. Gardez votre inventaire, vos étapes de vérification, et votre plan de retour arrière à portée de main, et vous réduirez les risques tout en gagnant les avantages de performance et de maintenabilité de PowerShell 7.