Comment puis-je exécuter PowerShell avec le runtime .NET 4?

234

Je mets à jour un script PowerShell qui gère certains assemblys .NET. Le script a été écrit pour les assemblys construits sur .NET 2 (la même version du framework avec lequel PowerShell s'exécute), mais doit maintenant fonctionner avec les assemblys .NET 4 ainsi que les assemblys .NET 2.

Étant donné que .NET 4 prend en charge l'exécution d'applications construites sur des versions plus anciennes du cadre, il semble que la solution la plus simple consiste à lancer PowerShell avec le runtime .NET 4 lorsque j'ai besoin de l'exécuter sur des assemblys .NET 4.

Comment puis-je exécuter PowerShell avec le runtime .NET 4?

Empereur XLII
la source
Duplicate de stackoverflow.com/questions/1940983/… .
Jeremy McGee
8
De nos jours, la solution la plus simple serait d'installer le CTP Powershell 3.0 qui utilise CLRVersion: 4.0.30319.1.
jon Z
2
Quiconque est toujours bloqué avec PowerShell 2, voir la réponse de Tim Lewis pour une solution localisée qui ne nécessite aucune modification de configuration à l'échelle de la machine.
Eric Eskildsen
1
Pour une solution sans système et sans fichier, voir cette réponse
vkrzv

Réponses:

147

PowerShell (le moteur) fonctionne correctement sous .NET 4.0. PowerShell (l'hôte de la console et l' ISE ) ne le font pas, simplement parce qu'ils ont été compilés avec des versions plus anciennes de .NET. Il existe un paramètre de registre qui changera le framework .NET chargé à l'échelle du système , ce qui permettra à son tour à PowerShell d'utiliser les classes .NET 4.0:

reg add hklm\software\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1
reg add hklm\software\wow6432node\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1

Pour mettre à jour uniquement l'ISE pour utiliser .NET 4.0, vous pouvez modifier le fichier de configuration ($ psHome \ powershell_ise.exe.config) pour avoir un bloc comme celui-ci:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
      <supportedRuntime version="v4.0.30319" />
    </startup>
</configuration>

Vous pouvez créer des applications .NET 4.0 qui appellent PowerShell à l'aide de l'API PowerShell (System.Management.Automation.PowerShell), mais ces étapes aideront à faire fonctionner les hôtes PowerShell intégrés sous .NET 4.0.


Supprimez les clés de registre lorsque vous n'en avez plus besoin. Ce sont des clés à l'échelle de la machine et migrent de force TOUTES les applications vers .NET 4.0, même les applications utilisant .net 2 et .net 3.5


Démarrer l'automatisation
la source
9
Juste pour être clair, powershell.exe (l'application hôte de la console) elle-même est une application native - non gérée.
Keith Hill
4
J'ai compris mon problème d'en haut. Vous devez placer le fichier de configuration dans le répertoire 64 bits lors de l'exécution sur un système d'exploitation 64 bits. L'exécutable PowerShell 32 bits semble reprendre très bien le changement à partir de là.
Chris McKenzie
11
Juste un petit conseil. Supprimez les clés de registre lorsque vous n'en avez plus besoin. Je viens de perdre une tonne de temps à essayer de découvrir pourquoi je n'ai pas pu créer un projet .NET 3.5 sur lequel je travaille.
Klark
7
La solution de modification de registre proposée a des effets secondaires désagréables si vous faites du multi-ciblage (c'est-à-dire l'écriture d'applications .NET 2.0 dans VS2010). Il faut se méfier.
Todd Sprang
9
Notez que Microsoft met fortement en garde contre cette opération: "Bien qu'il soit possible de forcer PowerShell 2.0 à s'exécuter avec .NET Framework 4.0 à l'aide de divers mécanismes tels que la création d'un fichier de configuration pour PowerShell ou la modification du registre, ces mécanismes ne sont pas pris en charge et peuvent avoir des effets secondaires négatifs sur d'autres fonctionnalités PowerShell telles que la communication à distance PowerShell et les applets de commande avec des assemblages en mode mixte. " connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 a une prise en charge native de .NET 4.0.
Timbo
238

La meilleure solution que j'ai trouvée se trouve dans le billet de blog Utilisation de nouvelles versions de .NET avec PowerShell . Cela permet à powershell.exe de s'exécuter avec des assemblys .NET 4.

Modifiez (ou créez) simplement $pshome\powershell.exe.configafin qu'il contienne les éléments suivants:

<?xml version="1.0"?> 
<configuration> 
    <startup useLegacyV2RuntimeActivationPolicy="true"> 
        <supportedRuntime version="v4.0.30319"/> 
        <supportedRuntime version="v2.0.50727"/> 
    </startup> 
</configuration> 

Remarques supplémentaires sur la configuration rapide:

Les emplacements et les fichiers dépendent quelque peu de la plate-forme; cependant, vous donnera un aperçu en ligne de la façon de faire fonctionner la solution pour vous.

  • Vous pouvez trouver l'emplacement de PowerShell sur votre ordinateur en exécutant cd $pshome dans la fenêtre Powershell (ne fonctionne pas à partir de l'invite DOS).
    • Le chemin sera quelque chose comme (exemple) C:\Windows\System32\WindowsPowerShell\v1.0\
  • Le nom de fichier dans lequel placer la configuration est: powershell.exe.configsi votre PowerShell.exeest en cours d'exécution (créez le fichier de configuration si nécessaire).
    • Si PowerShellISE.Exeest en cours d'exécution, vous devez créer son fichier de configuration compagnon en tant quePowerShellISE.Exe.config
cmo999
la source
23
Certainement la bonne façon de le faire. Cela modifie uniquement le comportement de Powershell, pas toutes les autres applications .NET sur votre machine ...
Erik A. Brandstadmoen
4
Cela fonctionne bien mais affecte tous vos PowerShell. Si vous ne voulez qu'une partie des fonctionnalités, faites une copie du dossier powershell, puis modifiez-y le fichier.
Matt
8
J'ai ajouté un fichier comme indiqué ci-dessus. Cependant, je ne peux plus exécuter PowerShell avec ce fichier présent - j'obtiens l'erreur "Le volume d'un fichier a été modifié en externe afin que le fichier ouvert ne soit plus valide." Des idées?
JoshL
13
@JoshL - sur un système 64 bits, j'ai trouvé que le fichier .exe.config doit aller dans SysWOW64 \ WindowsPowershell (le dossier 32 bits), même si vous essayez d'exécuter un PowerShell 64 bits. Sinon, vous obtenez l'erreur «modifié de l'extérieur».
Sam
4
Le fichier powershell.exe.config doit se trouver à deux endroits .... C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ et C: \ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome Reinstate Monica
28

Veuillez être TRÈS prudent avec l'utilisation de l'approche par clé de registre. Ce sont des clés à l'échelle de la machine et migrent forcément TOUTES les applications vers .NET 4.0.

De nombreux produits ne fonctionnent pas en cas de migration forcée et il s'agit d'une aide au test et non d'un mécanisme de qualité de production. Visual Studio 2008 et 2010, MSBuild , turbotax et une multitude de sites Web, SharePoint et ainsi de suite ne doivent pas être automatisés.

Si vous devez utiliser PowerShell avec 4.0, cela doit être fait par application avec un fichier de configuration, vous devriez vérifier avec l'équipe PowerShell la recommandation précise. Cela risque de casser certaines commandes PowerShell existantes.

Madhu Talluri
la source
Très bon point sur l'utilisation de la clé de registre. Heureusement, l'application de lancement avec le fichier de configuration fonctionne très bien. Nos scripts utilisent principalement les commandes du système de fichiers et les appels directs .NET, et nous n'avons remarqué aucun problème avec les commandes cassées. Étant donné que .NET 4 est largement rétrocompatible avec .NET 2.0, je ne pense pas qu'il y aurait de nombreuses commandes cassées (même si cela ne fait jamais de mal d'être prudent :).
Emperor XLII
26

Si vous n'avez besoin d'exécuter qu'une seule commande, bloc de script ou fichier de script dans .NET 4, essayez d'utiliser les fichiers de configuration d'activation à partir de .NET 4 pour démarrer une seule instance de PowerShell à l'aide de la version 4 du CLR.

Tous les détails:

http://blog.codeassassin.com/2011/03/23/executing-individual-powershell-commands-using-net-4/

Un exemple de module PowerShell:

https://gist.github.com/882528

Jason Stangroome
la source
21

Si vous êtes toujours bloqué sur PowerShell v1.0 ou v2.0, voici ma variante de l'excellente réponse de Jason Stangroome.

Créez un powershell4.cmdendroit sur votre chemin avec le contenu suivant:

@echo off
:: http://stackoverflow.com/questions/7308586/using-batch-echo-with-special-characters
if exist %~dp0powershell.exe.activation_config goto :run
echo.^<?xml version="1.0" encoding="utf-8" ?^>                 > %~dp0powershell.exe.activation_config
echo.^<configuration^>                                        >> %~dp0powershell.exe.activation_config
echo.  ^<startup useLegacyV2RuntimeActivationPolicy="true"^>  >> %~dp0powershell.exe.activation_config
echo.    ^<supportedRuntime version="v4.0"/^>                 >> %~dp0powershell.exe.activation_config
echo.  ^</startup^>                                           >> %~dp0powershell.exe.activation_config
echo.^</configuration^>                                       >> %~dp0powershell.exe.activation_config
:run
:: point COMPLUS_ApplicationMigrationRuntimeActivationConfigPath to the directory that this cmd file lives in
:: and the directory contains a powershell.exe.activation_config file which matches the executable name powershell.exe
set COMPLUS_ApplicationMigrationRuntimeActivationConfigPath=%~dp0
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe %*
set COMPLUS_ApplicationMigrationRuntimeActivationConfigPath=

Cela vous permettra de lancer une instance de la console PowerShell exécutée sous .NET 4.0.

Vous pouvez voir la différence sur mon système où j'ai PowerShell 2.0 en examinant la sortie des deux commandes suivantes exécutées à partir de cmd.

C:\>powershell -ExecutionPolicy ByPass -Command $PSVersionTable

Name                           Value
----                           -----
CLRVersion                     2.0.50727.5485
BuildVersion                   6.1.7601.17514
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           {1.0, 2.0}
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1


C:\>powershell4.cmd -ExecutionPolicy ByPass -Command $PSVersionTable

Name                           Value
----                           -----
PSVersion                      2.0
PSCompatibleVersions           {1.0, 2.0}
BuildVersion                   6.1.7601.17514
CLRVersion                     4.0.30319.18408
WSManStackVersion              2.0
PSRemotingProtocolVersion      2.1
SerializationVersion           1.1.0.1
Tim Lewis
la source
3
C'est de loin la meilleure réponse car il s'agit d'un changement très localisé et ne fait aucun changement persistant sur le système. Bon produit!
Sebastian
fantastique! Pouvez-vous m'aider ici? stackoverflow.com/questions/39801315/…
johny why
@TimLewis, est-il possible d'envoyer plusieurs instructions à la même instance ps4.cmd?
johny pourquoi
@johnywhy, l'envoi de plusieurs instructions au .cmd équivaut à l'envoi de plusieurs instructions au .exe car le .cmd utilise% * pour transmettre tous ses paramètres au .exe. Cela ne fait cependant aucune différence, car vous devez toujours faire attention à la façon dont cmd.exe analyse la ligne de commande lorsqu'il transmet les paramètres à l'exécutable qu'il lance. Je vais jeter un oeil à votre autre question de débordement de pile et y aborder les détails.
Tim Lewis
J'ai essayé d'utiliser cette technique en combinaison avec le paramètre de ligne de commande -Version docs.microsoft.com/en-us/powershell/scripting/core-powershell/… Malheureusement, cela ne fonctionne pas; ma dernière version de PowerShell (5.1.17134.407), déterminée à partir de $ PSVersionTable.PSVersion, est lancée à la place.
eisenpony
17

Voici le contenu du fichier de configuration que j'ai utilisé pour prendre en charge les assemblys .NET 2.0 et .NET 4:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- http://msdn.microsoft.com/en-us/library/w4atty68.aspx -->
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" />
    <supportedRuntime version="v2.0.50727" />
  </startup>
</configuration>

En outre, voici une version simplifiée du code compatible PowerShell 1.0 que j'ai utilisé pour exécuter nos scripts à partir des arguments de ligne de commande passés:

class Program {
  static void Main( string[] args ) {
    Console.WriteLine( ".NET " + Environment.Version );

    string script = "& " + string.Join( " ", args );
    Console.WriteLine( script );
    Console.WriteLine( );

    // Simple host that sends output to System.Console
    PSHost host = new ConsoleHost( this );
    Runspace runspace = RunspaceFactory.CreateRunspace( host );

    Pipeline pipeline = runspace.CreatePipeline( );
    pipeline.Commands.AddScript( script );

    try {
      runspace.Open( );
      IEnumerable<PSObject> output = pipeline.Invoke( );
      runspace.Close( );

      // ...
    }
    catch( RuntimeException ex ) {
      string psLine = ex.ErrorRecord.InvocationInfo.PositionMessage;
      Console.WriteLine( "error : {0}: {1}{2}", ex.GetType( ), ex.Message, psLine );
      ExitCode = -1;
    }
  }
}

En plus de la gestion des erreurs de base illustrée ci-dessus, nous injectons également une trapinstruction dans le script pour afficher des informations de diagnostic supplémentaires (similaires à la fonction Resolve-Error de Jeffrey Snover ).

Empereur XLII
la source
10

Les autres réponses datent d'avant 2012 et se concentrent sur le «piratage» de PowerShell 1.0 ou PowerShell 2.0 pour cibler les nouvelles versions du .NET Framework et du Common Language Runtime (CLR).

Cependant, comme cela a été écrit dans de nombreux commentaires, depuis 2012 (lorsque PowerShell 3.0 est arrivé), une bien meilleure solution consiste à installer la dernière version de PowerShell . Il ciblera automatiquement CLR v4.0.30319. Cela signifie .NET 4.0, 4.5, 4.5.1, 4.5.2 ou 4.6 (attendu en 2015) car toutes ces versions sont des remplacements sur place les unes des autres. Utilisez $PSVersionTableou consultez le thread de version de PowerShell installé si vous n'êtes pas sûr de votre version de PowerShell.

Au moment de la rédaction du présent document, la dernière version de PowerShell est 4.0, et elle peut être téléchargée avec Windows Management Framework (lien de recherche Google) .

Jeppe Stig Nielsen
la source
2
La configuration système requise pour Windows Management Framework 4.0 (ils sont similaires pour 3.0) sont: Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.
Peter Mortensen
9

En fait, vous pouvez faire fonctionner PowerShell à l'aide de .NET 4 sans affecter les autres applications .NET. J'avais besoin de le faire pour utiliser la nouvelle propriété "Host" HttpWebRequest, mais changer le "OnlyUseLatestCLR" a cassé Fiddler car cela ne pouvait pas être utilisé sous .NET 4.

Les développeurs de PowerShell ont évidemment prévu cela, et ils ont ajouté une clé de registre pour spécifier la version du Framework à utiliser. Un léger problème est que vous devez vous approprier la clé de registre avant de la modifier, car même les administrateurs n'y ont pas accès.

  • HKLM: \ Software \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (64 bits et 32 ​​bits)
  • HKLM: \ Software \ Wow6432Node \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (32 bits sur une machine 64 bits)

Remplacez la valeur de cette clé par la version requise. Gardez à l'esprit que certains snapins ne peuvent plus se charger à moins qu'ils ne soient compatibles .NET 4 (WASP est le seul avec lequel j'ai eu des problèmes, mais je ne l'utilise pas vraiment de toute façon). VMWare , SQL Server 2008 , PSCX, Active Directory (Microsoft et Quest Software ) et SCOM fonctionnent tous correctement.

Justin Yancey
la source
+1 Il s'agit d'une alternative très importante (et meilleure) que l'autre entrée reg qui affectera toutes les applications .net, mais cette solution n'affecte que powershell.
Christian Mikkelsen
Après avoir implémenté le "OnlyUseLatestCLR" mon Fiddler s'est cassé ainsi que certains scripts PowerShell qui ne fonctionnent plus en raison de l'impossibilité de contacter certains serveurs. J'ai modifié manuellement les valeurs à 0 dans le regedt32, et maintenant tout fonctionne à nouveau. Merci!
Neville
Que sont WASP, PSCX et SCOM (dans ce contexte)?
Peter Mortensen
7

Si vous ne souhaitez pas modifier le registre ou les fichiers app.config, une autre manière consiste à créer une application console .NET 4 simple qui imite ce que fait PowerShell.exe et héberge PowerShell ConsoleShell.

Voir Option 2 - Hébergement de Windows PowerShell vous-même

Tout d'abord, ajoutez une référence aux assemblys System.Management.Automation et Microsoft.PowerShell.ConsoleHost qui se trouvent sous % programfiles% \ Reference Assemblies \ Microsoft \ WindowsPowerShell \ v1.0

Utilisez ensuite le code suivant:

using System;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;

namespace PSHostCLRv4
{
    class Program
    {
        static int Main(string[] args)
        {
            var config = RunspaceConfiguration.Create();
                return ConsoleShell.Start(
                config,
                "Windows PowerShell - Hosted on CLR v4\nCopyright (C) 2010 Microsoft Corporation. All rights reserved.",
                "",
                args
            );
        }
    }
}
Grant Holliday
la source
6

Tout comme une autre option, la dernière version de PoshConsole comprend des fichiers binaires ciblés sur .NET 4 RC (qui fonctionnent bien par rapport à la version RTM) sans aucune configuration.

Jaykul
la source
1

Exécutez simplement powershell.exe avec COMPLUS_versionla variable d'environnement définie sur v4.0.30319. Par exemple, à partir de cmd.exe ou d'un fichier .bat:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
vkrzv
la source