Sur Windows Server 2019, PowerShell peut se fermer aussitôt en affichant “Starting the CLR failed with HRESULT 80070005” (Accès refusé). Ce guide fournit une résolution éprouvée (.NET Framework, ACL, AppLocker/WDAC), un diagnostic pas‑à‑pas et un contournement fiable via PowerShell 7.
PowerShell qui se ferme au lancement avec erreur d’accès refusé
En environnement Windows Server 2019 Datacenter (version 1809, build 17763.5576), l’ouverture de Windows PowerShell 5.1 peut brièvement afficher la fenêtre puis la refermer. Depuis cmd.exe
, la commande powershell
retourne : Starting the CLR failed with HRESULT 80070005 — ce qui correspond à une erreur Access denied.
Les tentatives classiques (mises à jour cumulatives, DISM avec source ISO, tentative de retrait d’une “fonctionnalité PowerShell”, etc.) n’y changent parfois rien. Aucun journal “parlant” n’est forcément créé et il n’y a pas de minidump, car l’échec intervient très tôt : le Common Language Runtime du .NET Framework ne parvient pas à démarrer.
Ce que cela signifie concrètement
Windows PowerShell 5.1 repose sur le runtime .NET Framework 4.x (CLR v4.0.30319). Si ce runtime est endommagé, bridé par des droits ou bloqué par une politique, PowerShell s’arrête net. Le code 0x80070005
pointe vers un accès refusé : fichier, dossier, clé de Registre, ou chargement d’assembly interdit.
Causes probables
- Corruption partielle ou installation incomplète de .NET Framework 4.8 (fichiers GAC, composants CLR, Registre).
- ACL erronées sur
C:\Windows\Microsoft.NET\*
ou sur le Global Assembly Cache (C:\Windows\Microsoft.NET\assembly
). - Politiques d’exécution AppLocker, WDAC (Code Integrity) ou Software Restriction Policies bloquant
powershell.exe
ou des DLL .NET. - EDR/antivirus interférant avec le chargement des DLL.
- Profil utilisateur corrompu ou variables d’environnement atypiques (
COMPLUS_*
) injectées par un outil. - Confusion sur les “fonctionnalités Windows” : PowerShell 5.1 fait partie de l’OS (non désinstallable), seule la “console PowerShell 2.0” est une fonctionnalité optionnelle.
Réponse et solution brève
- Réparer ou réinstaller .NET Framework 4.8 avec l’installateur hors‑ligne ; au besoin exécuter d’abord l’outil de réparation .NET. Redémarrer ensuite.
- Installer PowerShell 7 en parallèle (MSI), qui s’appuie sur .NET moderne et est indépendant du .NET Framework 4.x.
Si PowerShell 7 (pwsh.exe
) fonctionne alors que PowerShell 5.1 ne démarre pas, le problème est quasi exclusivement cantonné au runtime .NET Framework.
Guide pas à pas
Réparer ou réinstaller .NET Framework
Procédure recommandée :
- Télécharger l’installateur hors‑ligne de .NET Framework 4.8 sur un poste sûr et le copier sur le serveur affecté.
- Exécuter d’abord l’outil officiel de réparation .NET (.NET Framework Repair Tool) si disponible dans votre référentiel interne.
- Lancer ensuite l’installateur .NET 4.8 en mode réparation ; si la réparation échoue, procéder à une réinstallation propre.
- Redémarrer le serveur.
- Tester immédiatement :
cmd.exe
→powershell -nologo -noprofile -c "$PSVersionTable.PSVersion"
.
Bon à savoir : Windows Server 2019 ne prend pas en charge .NET Framework 4.8.1 ; restez sur 4.8 pour ce système.
Installer PowerShell en version moderne en parallèle
Pour garantir la continuité d’exploitation :
- Installer PowerShell 7 via le package MSI (canal stable). L’installation n’écrase pas PowerShell 5.1.
- Vérifier l’exécution :
cmd.exe
→pwsh -NoLogo
puis$PSVersionTable
. - Le cas échéant, ajouter
C:\Program Files\PowerShell\7
auPATH
système et créer un raccourci pour les administrateurs.
Si pwsh
fonctionne tandis que powershell.exe
échoue, vous avez une preuve solide d’un problème circonscrit à .NET Framework.
Validation rapide après réparation
- Bitness : tester les deux exécutables :
- 64 bits :
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
- 32 bits :
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
- 64 bits :
- À blanc :
powershell -noprofile -nologo
(évite toute influence de profil). - Version :
powershell -c "$PSVersionTable"
etpowershell -c "[Environment]::Version"
.
Contrôles essentiels côté .NET Framework
Confirmer la présence de la version installée
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release
Si la valeur Release
ne correspond pas à .NET 4.8 (par ex. valeur trop basse), mettez à niveau. À défaut d’un tableau de correspondance, retenez l’heuristique : une valeur indiquant au moins 4.8 est requise sur Windows Server 2019.
Contrôler les autorisations de fichiers
Des ACL dégradées sur les dossiers .NET/CLR provoquent typiquement l’erreur d’accès refusé au démarrage du CLR.
icacls C:\Windows\Microsoft.NET\ /T > C:\temp\acl_dotnet.txt
icacls C:\Windows\Microsoft.NET\assembly /T >> C:\temp\acl_dotnet.txt
Inspectez acl_dotnet.txt
: des lignes ACCESS DENIED ou des propriétaires anormaux (Administrators à la place de TrustedInstaller, par exemple) doivent alerter. Corrigez à partir d’un serveur sain (export/import d’ACL), ou laissez SFC/DISM restaurer les descripteurs par défaut.
Examiner les politiques de contrôle d’exécution
AppLocker/WDAC/SRP peuvent bloquer autant l’exécutable que les DLL .NET.
- Journaux AppLocker : Observateur d’événements → Applications and Services Logs ▸ Microsoft ▸ Windows ▸ AppLocker.
- Journaux WDAC/Code Integrity : Observateur d’événements → Applications and Services Logs ▸ Microsoft ▸ Windows ▸ CodeIntegrity.
- Si des règles existent, autorisez explicitement
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
et les répertoires .NET (C:\Windows\Microsoft.NET\*
). - En mode audit, vérifiez la présence d’entrées “would be blocked”. Convertissez ensuite en mode imposé une fois validé.
Localiser l’accès refusé avec Process Monitor
Process Monitor (Sysinternals) est l’outil le plus efficace pour identifier la ressource exacte refusée :
- Filtrer Process Name = powershell.exe.
- Lancer PowerShell pour reproduire l’échec, puis arrêter la capture.
- Trier/filtrer sur Result = ACCESS DENIED et analyser le premier refus.
Les chemins cités (DLL du CLR, GAC, clés Registre HKLM\SOFTWARE\Classes
/HKCR
, sous‑clés .NET) guident la correction d’ACL ou la mise à jour des règles AppLocker/WDAC.
Activer les journaux de liaison d’assembly
À n’activer que temporairement :
reg add "HKLM\SOFTWARE\Microsoft\Fusion" /v ForceLog /t REG_DWORD /d 1 /f
reg add "HKLM\SOFTWARE\Microsoft\Fusion" /v LogFailures /t REG_DWORD /d 1 /f
reg add "HKLM\SOFTWARE\Microsoft\Fusion" /v LogResourceBinds /t REG_DWORD /d 1 /f
reg add "HKLM\SOFTWARE\Microsoft\Fusion" /v LogPath /t REG_SZ /d C:\FusionLogs /f
mkdir C:\FusionLogs
Relancez PowerShell pour générer des traces détaillant le chargement d’assemblies. Remettez ensuite les valeurs à zéro et supprimez le dossier de logs pour éviter toute collecte persistante.
Vérifications système complémentaires
- SFC : même si DISM est passé, une vérification d’intégrité peut restaurer des fichiers protégés.
sfc /scannow
- Fonctionnalités Windows : la “Console PowerShell 2.0” est une option distincte et obsolète. Ne pas confondre avec PowerShell 5.1 (composant de l’OS non désinstallable).
- Nouveau profil : créer un administrateur local neuf et tester pour exclure un profil corrompu.
- EDR/AV : désactiver temporairement (si vos politiques le permettent) pour écarter un blocage de DLL au chargement.
Plan de diagnostic structuré
Symptôme/constat | Ce que cela indique | Action prioritaire |
---|---|---|
PowerShell 5.1 se ferme immédiatement, 0x80070005 | Échec du CLR .NET 4.x (accès refusé) | Réparer/réinstaller .NET 4.8 puis redémarrer |
pwsh.exe fonctionne | Problème cantonné à .NET Framework | Poursuivre réparation .NET 4.8, corriger ACL/WDAC |
Événements AppLocker/CodeIntegrity | Blocage par politique | Créer des règles d’autorisation ciblées |
Procmon montre ACCESS DENIED sur GAC | ACL corrompues | Restaurer ACL/SFC, aligner avec un serveur sain |
Échec identique sous nouvel utilisateur | Cause système | Focaliser sur .NET/ACL/politiques |
Procédure de correction des ACL en sécurité
Si un refus précis est identifié (par exemple dans C:\Windows\Microsoft.NET\assembly
) :
- Éviter les changements massifs (pas de
icacls C:\Windows /grant ...
). - Comparer avec un serveur sain :
icacls "C:\Windows\Microsoft.NET\assembly" /T /save C:\temp\good_gac.acl icacls "C:\Windows\Microsoft.NET\assembly" /T /verify
- Sur le serveur affecté, restaurer précisément les entrées manquantes sur les chemins signalés par Procmon.
- Si des fichiers protégés sont atteints, laisser SFC les rétablir plutôt que de reprendre la propriété manuellement.
En dernier recours, vous pouvez exporter les ACL d’un serveur sain (/save
) et les /restore
sur les mêmes chemins, après sauvegarde de l’état actuel et approbation.
Points d’attention qui font gagner du temps
- Ne vous acharnez pas à désinstaller une “fonctionnalité PowerShell” : cela cible la console obsolète, pas PowerShell 5.1 intégré à l’OS.
- N’essayez pas d’installer .NET 4.8.1 sur Windows Server 2019 : ce n’est pas la bonne base.
- Testez les deux architectures (System32/SysWOW64) pour cerner un blocage 32/64 bits.
- Vérifiez le chemin résolu :
where powershell.exe
doit pointer versSystem32\WindowsPowerShell\v1.0
. Une redirection ou un binaire remplacé par un agent peut être en cause. - Variables d’environnement : traquez des
COMPLUS_*
inhabituelles dans Système et Utilisateur. Supprimez‑les pour tester.
Exemples de commandes utiles
:: Vérifier la version .NET installée
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release
\:: Lancer PowerShell sans profil
powershell -noprofile -nologo
\:: Tester l’exécutable 64 et 32 bits
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -nologo
"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -nologo
\:: Vérifier l'intégrité des fichiers système
sfc /scannow
\:: Capturer les ACL de .NET
icacls C:\Windows\Microsoft.NET\ /T > C:\temp\acl\_dotnet.txt
\:: Activer/collecter les logs Fusion (temporaire)
reg add "HKLM\SOFTWARE\Microsoft\Fusion" /v LogFailures /t REG\_DWORD /d 1 /f
Diagnostic avancé avec Process Monitor
Quelques filtres qui aident :
- Process Name est
powershell.exe
- Result contient
ACCESS DENIED
ouNAME NOT FOUND
(pour repérer une recherche d’assembly non trouvée qui débouche sur un refus ailleurs) - Path contient
\Microsoft.NET\
,\assembly\
,mscor*
,clr.dll
,fusion.dll
- Operation :
CreateFile
,Load Image
,RegOpenKey
,RegQueryValue
Interprétez dans l’ordre d’apparition. Le premier refus bien formé est souvent la cause, les refus suivants ne sont que des effets de bord. Corrigez l’ACL ou la règle AppLocker/WDAC sur l’élément pointé, puis retestez.
Cas d’école et remédiations
Traces ou indices | Cause la plus probable | Remède recommandé |
---|---|---|
Refus sur C:\Windows\Microsoft.NET\assembly\GAC_MSIL\* | ACL GAC altérées | Restaurer ACL via SFC ou à partir d’un serveur sain |
AppLocker journalise un blocage sur powershell.exe ou clr.dll | Règle d’exécution trop stricte | Ajouter une règle d’autorisation (chemin & signature) et repasser en mode imposé après validation |
Release .NET incohérent / installateur en réparation | .NET incomplet/cassé | Réparer .NET 4.8 hors‑ligne et redémarrer |
pwsh ok, powershell ko | Problème spécifique à .NET Framework | Stabiliser .NET 4.8 ; garder PowerShell 7 comme standard |
Industrialisation et prévention
- Standardiser PowerShell 7 sur les serveurs (sans retirer PowerShell 5.1) : vous gagnez en robustesse et en sécurité.
- État de référence des ACL : conservez un export
icacls
des dossiers .NET sur un serveur “golden” pour comparaison rapide. - Politiques AppLocker/WDAC : privilégiez des règles par signature éditeur/chemin système, pas des chemins fragiles.
- Surveillance : activez l’audit des échecs de chargement pour réagir en amont (journaux Fusion temporaires lors des déploiements sensibles).
- Gestion des correctifs : inclure la réparation .NET et un test automatisé de lancement PowerShell dans vos pipelines post‑patch.
Résumé actionnable
- Réparer/réinstaller .NET Framework 4.8 puis redémarrer.
- Installer PowerShell 7 en parallèle pour assurer la continuité d’exploitation.
- Si échec : diagnostiquer l’ACCESS DENIED avec Process Monitor et vérifier AppLocker/WDAC ainsi que les ACL sur
C:\Windows\Microsoft.NET\*
et le GAC. - Exécuter SFC, contrôler les journaux spécialisés (.NET/AppLocker), tester avec un nouveau profil.
Annexe : scripts minimaux pour gagner du temps
Collecte rapide à exécuter depuis cmd.exe
(en tant qu’administrateur) :
:: Dossier de collecte
mkdir C:\Temp\PSFail >nul 2>&1
\:: Version .NET (Release)
reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release > C:\Temp\PSFail\dotnet\_release.txt
\:: ACL .NET
icacls "C:\Windows\Microsoft.NET" /T > C:\Temp\PSFail\acl\_dotnet.txt
icacls "C:\Windows\Microsoft.NET\assembly" /T >> C:\Temp\PSFail\acl\_dotnet.txt
\:: Emplacements PowerShell
where powershell.exe > C:\Temp\PSFail\where\_powershell.txt
\:: Journaux AppLocker et Code Integrity (événements récents)
wevtutil qe "Microsoft-Windows-AppLocker/EXE and DLL" /c:50 /f\:text > C:\Temp\PSFail\applocker.txt
wevtutil qe "Microsoft-Windows-CodeIntegrity/Operational" /c:50 /f\:text > C:\Temp\PSFail\codeintegrity.txt
\:: Test de lancement à blanc
powershell -noprofile -nologo -c "\$PSVersionTable" > C:\Temp\PSFail\ps\_try.txt 2>&1
Conclusion
Le symptôme “Starting the CLR failed with HRESULT 80070005” résulte presque toujours d’un problème autour du .NET Framework ou d’un blocage d’accès au moment de charger le CLR. La démarche la plus efficace reste : réparer/réinstaller .NET 4.8, valider avec PowerShell 7, puis cibler l’accès refusé via Process Monitor et l’audit des politiques (AppLocker/WDAC). Avec quelques garde‑fous (référence d’ACL, règles d’exécution bien calibrées, tests post‑patch), vous éliminez durablement ce scénario sur Windows Server 2019.
En bref : corrigez .NET, isolez les refus, normalisez PowerShell 7 et documentez vos ACL/politiques — vous retrouverez un PowerShell stable et prévisible.