Wie kann ich PowerShell mit der .NET 4-Laufzeit ausführen?

234

Ich aktualisiere ein PowerShell-Skript, das einige .NET-Assemblys verwaltet. Das Skript wurde für Assemblys geschrieben, die für .NET 2 erstellt wurden (dieselbe Version des Frameworks, mit dem PowerShell ausgeführt wird), muss jetzt jedoch sowohl mit .NET 4-Assemblys als auch mit .NET 2-Assemblys arbeiten.

Da .NET 4 das Ausführen von Anwendungen unterstützt, die für ältere Versionen des Frameworks erstellt wurden, scheint es die einfachste Lösung zu sein, PowerShell mit der .NET 4-Laufzeit zu starten, wenn ich es für .NET 4-Assemblys ausführen muss.

Wie kann ich PowerShell mit der .NET 4-Laufzeit ausführen?

Kaiser XLII
quelle
Duplikat von stackoverflow.com/questions/1940983/… .
Jeremy McGee
8
Heutzutage wäre die einfachste Lösung die Installation des Powershell 3.0 CTP, das CLRVersion: 4.0.30319.1 verwendet.
Jon Z
2
Wenn Sie immer noch an PowerShell 2 festhalten, finden Sie in Tim Lewis 'Antwort eine lokalisierte Lösung, bei der keine maschinenweite Konfiguration bearbeitet werden muss.
Eric Eskildsen
1
Für eine nicht systemweite und fileless Lösung siehe diese Antwort
vkrzv

Antworten:

147

PowerShell (die Engine) läuft unter .NET 4.0 einwandfrei. PowerShell (der Konsolenhost und die ISE ) tun dies nicht, nur weil sie gegen ältere Versionen von .NET kompiliert wurden. Es gibt eine Registrierungseinstellung, die das systemweit geladene .NET Framework ändert , wodurch PowerShell wiederum .NET 4.0-Klassen verwenden kann:

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

Um nur die ISE für die Verwendung von .NET 4.0 zu aktualisieren, können Sie die Konfigurationsdatei ($ psHome \ Powershell_ise.exe.config) so ändern, dass sie einen Block wie den folgenden enthält:

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

Sie können .NET 4.0-Anwendungen, die PowerShell aufrufen, mithilfe der PowerShell-API (System.Management.Automation.PowerShell) erstellen. Diese Schritte helfen jedoch dabei, die sofort einsatzbereiten PowerShell-Hosts unter .NET 4.0 zum Laufen zu bringen.


Entfernen Sie die Registrierungsschlüssel, wenn Sie sie nicht mehr benötigen. Dies sind maschinenweite Schlüssel, die ALLE Anwendungen zwangsweise auf .NET 4.0 migrieren, auch Anwendungen, die .net 2 und .net 3.5 verwenden


Starten Sie die Automatisierung
quelle
9
Um ganz klar zu sein, Powershell.exe (die Konsolenhost-App) selbst ist eine native Anwendung - nicht verwaltet.
Keith Hill
4
Ich habe mein Problem von oben herausgefunden. Sie müssen die Konfigurationsdatei im 64-Bit-Verzeichnis ablegen, wenn Sie auf einem 64-Bit-Betriebssystem ausgeführt werden. Die ausführbare 32-Bit-Powershell-Datei scheint die Änderung von dort aus gut aufzunehmen.
Chris McKenzie
11
Nur ein kleiner Rat. Entfernen Sie die Registrierungsschlüssel, wenn Sie sie nicht mehr benötigen. Ich habe gerade eine Menge Zeit verloren, um herauszufinden, warum ich kein .NET 3.5-Projekt erstellen konnte, an dem ich arbeite.
Klark
7
Die vorgeschlagene Lösung zur Änderung der Registrierung hat schlimme Nebenwirkungen, wenn Sie Multi-Targeting durchführen (dh .NET 2.0-Apps in VS2010 schreiben). In acht nehmen.
Todd Sprang
9
Beachten Sie, dass Microsoft nachdrücklich davor warnt: "Es ist zwar möglich, PowerShell 2.0 zur Ausführung mit .NET Framework 4.0 zu zwingen, indem verschiedene Mechanismen verwendet werden, z. B. das Erstellen einer Konfigurationsdatei für PowerShell oder das Bearbeiten der Registrierung. Diese Mechanismen werden jedoch nicht unterstützt und können dies auch tun." negative Nebenwirkungen auf andere PowerShell-Funktionen wie PowerShell-Remoting und Cmdlets mit Assemblys im gemischten Modus. " connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 bietet native Unterstützung für .NET 4.0.
Timbo
238

Die beste Lösung, die ich gefunden habe, ist im Blogbeitrag Verwenden neuerer Versionen von .NET mit PowerShell . Dadurch kann Powershell.exe mit .NET 4-Assemblys ausgeführt werden.

Ändern Sie einfach (oder erstellen Sie es) $pshome\powershell.exe.configso, dass es Folgendes enthält:

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

Zusätzliche, schnelle Einrichtungshinweise:

Speicherorte und Dateien sind etwas plattformabhängig. Sie erhalten jedoch einen Überblick darüber, wie die Lösung für Sie funktioniert.

  • Sie können den Speicherort von PowerShell auf Ihrem Computer finden, indem Sie ihn cd $pshome im Powershell-Fenster ausführen (funktioniert nicht über die DOS-Eingabeaufforderung).
    • Pfad wird so etwas wie (Beispiel) sein C:\Windows\System32\WindowsPowerShell\v1.0\
  • Der Dateiname, in den die Konfiguration eingefügt werden soll, lautet: powershell.exe.configWenn Ihr PowerShell.exeausgeführt wird (erstellen Sie gegebenenfalls die Konfigurationsdatei).
    • Wenn ausgeführt PowerShellISE.Exewird, müssen Sie die zugehörige Konfigurationsdatei als erstellenPowerShellISE.Exe.config
cmo999
quelle
23
Auf jeden Fall der richtige Weg. Dies ändert nur das Verhalten von Powershell, nicht jede andere .NET-App auf Ihrem Computer ...
Erik A. Brandstadmoen
4
Dies funktioniert gut, betrifft jedoch alle Ihre PowerShell. Wenn Sie nur einen Teil der Funktionen nutzen möchten, erstellen Sie eine Kopie des Powershell-Ordners und bearbeiten Sie die Datei dort.
Matt
8
Ich habe eine Datei wie oben angegeben hinzugefügt. Ich kann PowerShell jedoch nicht mehr ausführen, wenn diese Datei vorhanden ist. Ich erhalte die Fehlermeldung "Das Volume für eine Datei wurde extern geändert, sodass die geöffnete Datei nicht mehr gültig ist." Irgendwelche Ideen?
JoshL
13
@JoshL - Auf einem 64-Bit-System muss die .exe.config in SysWOW64 \ WindowsPowershell (den 32-Bit-Ordner) verschoben werden, auch wenn Sie versuchen, 64-Bit-Powershell auszuführen. Andernfalls wird der Fehler "extern geändert" angezeigt.
Sam
4
Die Powershell.exe.config muss sich an zwei Stellen befinden: C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ und C: \ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome Reinstate Monica
28

Bitte seien Sie SEHR vorsichtig bei der Verwendung des Registrierungsschlüssel-Ansatzes. Dies sind maschinenweite Schlüssel, mit denen ALLE Anwendungen zwangsweise auf .NET 4.0 migriert werden .

Viele Produkte funktionieren nicht, wenn sie zwangsweise migriert werden. Dies ist eine Testhilfe und kein Mechanismus für die Produktionsqualität. Visual Studio 2008 und 2010, MSBuild , Turbotax und eine Vielzahl von Websites, SharePoint usw. sollten nicht automatisch migriert werden.

Wenn Sie PowerShell mit 4.0 verwenden müssen, sollte dies auf Anwendungsbasis mit einer Konfigurationsdatei erfolgen. Erkundigen Sie sich beim PowerShell-Team nach der genauen Empfehlung. Dadurch werden wahrscheinlich einige vorhandene PowerShell-Befehle beschädigt.

Madhu Talluri
quelle
Sehr guter Punkt zur Verwendung des Registrierungsschlüssels. Glücklicherweise funktioniert die Launcher-Anwendung mit der Konfigurationsdatei einwandfrei. Unsere Skripte verwenden hauptsächlich Dateisystembefehle und direkte .NET-Aufrufe, und wir haben keine Probleme mit fehlerhaften Befehlen festgestellt. Da .NET 4 weitgehend abwärtskompatibel mit .NET 2.0 ist, würde ich es nicht für wahrscheinlich halten, dass es viele fehlerhafte Befehle geben würde (obwohl es nie weh tut, Vorsichtsmaßnahmen zu treffen :).
Kaiser XLII
26

Wenn Sie in .NET 4 nur einen einzigen Befehl, Skriptblock oder eine einzelne Skriptdatei ausführen müssen, versuchen Sie, mithilfe von Aktivierungskonfigurationsdateien aus .NET 4 nur eine einzelne Instanz von PowerShell mit Version 4 der CLR zu starten.

Alle Einzelheiten:

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

Ein Beispiel für ein PowerShell-Modul:

https://gist.github.com/882528

Jason Stangroome
quelle
21

Wenn Sie immer noch an PowerShell v1.0 oder v2.0 festhalten, finden Sie hier meine Variation der hervorragenden Antwort von Jason Stangroome.

Erstellen Sie eine Stelle powershell4.cmdauf Ihrem Pfad mit den folgenden Inhalten:

@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=

Auf diese Weise können Sie eine Instanz der Powershell-Konsole starten, die unter .NET 4.0 ausgeführt wird.

Sie können den Unterschied auf meinem System mit PowerShell 2.0 erkennen, indem Sie die Ausgabe der folgenden zwei Befehle untersuchen, die von cmd ausgeführt werden.

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
quelle
3
Dies ist bei weitem die beste Antwort, da es sich um eine sehr lokalisierte Änderung handelt und keine dauerhaften Änderungen am System vorgenommen werden. Gutes Zeug!
Sebastian
Fantastisch! Kannst du hier helfen? stackoverflow.com/questions/39801315/…
Johny warum
@ TimLewis, ist es möglich, mehrere Anweisungen an dieselbe ps4.cmd-Instanz zu senden?
Johny, warum
@johnywhy, das Senden mehrerer Anweisungen an die .cmd entspricht dem Senden mehrerer Anweisungen an die .exe, da die .cmd% * verwendet, um alle ihre Parameter an die .exe weiterzuleiten. Dies macht jedoch keinen Unterschied, da Sie immer noch vorsichtig sein müssen, wie cmd.exe die Befehlszeile analysiert, wenn die Parameter an die ausführbare Datei übergeben werden, die gestartet wird. Ich werde einen Blick auf Ihre andere Frage zum Stapelüberlauf werfen und dort Einzelheiten ansprechen.
Tim Lewis
Ich habe versucht, diese Technik in Kombination mit dem Befehlszeilenparameter -Version docs.microsoft.com/en-us/powershell/scripting/core-powershell/… zu verwenden. Leider funktioniert sie nicht. Stattdessen wird meine neueste Version von PowerShell (5.1.17134.407) gestartet, die aus $ PSVersionTable.PSVersion ermittelt wurde.
Eisenpony
17

Hier ist der Inhalt der Konfigurationsdatei, mit der ich sowohl .NET 2.0- als auch .NET 4-Assemblys unterstützt habe:

<?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>

Außerdem ist hier eine vereinfachte Version des PowerShell 1.0-kompatiblen Codes, mit dem ich unsere Skripte aus den übergebenen Befehlszeilenargumenten ausgeführt habe:

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;
    }
  }
}

Zusätzlich zu der oben gezeigten grundlegenden Fehlerbehandlung fügen wir eine trapAnweisung in das Skript ein, um zusätzliche Diagnoseinformationen anzuzeigen (ähnlich der Resolve-Error- Funktion von Jeffrey Snover ).

Kaiser XLII
quelle
10

Die anderen Antworten stammen aus der Zeit vor 2012 und konzentrieren sich darauf, PowerShell 1.0 oder PowerShell 2.0 zu "hacken", um auf neuere Versionen von .NET Framework und Common Language Runtime (CLR) abzuzielen.

Wie bereits in vielen Kommentaren erwähnt, besteht eine viel bessere Lösung seit 2012 (als PowerShell 3.0 auf den Markt kam) darin, die neueste Version von PowerShell zu installieren . Es wird automatisch auf CLR abzielen v4.0.30319. Dies bedeutet .NET 4.0, 4.5, 4.5.1, 4.5.2 oder 4.6 (voraussichtlich 2015), da alle diese Versionen direkt voneinander ersetzt werden. Verwenden $PSVersionTableSie den Thread Installierte PowerShell-Version ermitteln oder lesen Sie ihn, wenn Sie sich über Ihre PowerShell-Version nicht sicher sind.

Zum Zeitpunkt des Schreibens ist die neueste Version von PowerShell 4.0 und kann mit dem Windows Management Framework (Google-Suchlink) heruntergeladen werden .

Jeppe Stig Nielsen
quelle
2
Die Systemanforderungen für Windows Management Framework 4.0 (sie sind für 3.0 ähnlich) sind: Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.
Peter Mortensen
9

Tatsächlich können Sie PowerShell mit .NET 4 ausführen, ohne andere .NET-Anwendungen zu beeinträchtigen. Ich musste dies tun, um die neue HttpWebRequest "Host" -Eigenschaft zu verwenden, aber das Ändern der "OnlyUseLatestCLR" brach Fiddler, da dies unter .NET 4 nicht verwendet werden konnte.

Die Entwickler von PowerShell haben dies offensichtlich vorausgesehen und einen Registrierungsschlüssel hinzugefügt, um anzugeben, welche Version des Frameworks verwendet werden soll. Ein kleines Problem ist, dass Sie den Registrierungsschlüssel in Besitz nehmen müssen, bevor Sie ihn ändern können, da selbst Administratoren keinen Zugriff haben.

  • HKLM: \ Software \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (64 Bit und 32 Bit)
  • HKLM: \ Software \ Wow6432Node \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (32-Bit auf 64-Bit-Computer)

Ändern Sie den Wert dieses Schlüssels in die erforderliche Version. Beachten Sie jedoch, dass einige Snapins möglicherweise nicht mehr geladen werden, es sei denn, sie sind .NET 4-kompatibel (WASP ist das einzige, mit dem ich Probleme hatte, aber ich verwende es trotzdem nicht wirklich). VMWare , SQL Server 2008 , PSCX, Active Directory (Microsoft und Quest Software ) und SCOM funktionieren einwandfrei.

Justin Yancey
quelle
+1 Dies ist eine sehr wichtige Alternative (und besser) als der andere Registrierungseintrag, der alle .net-Anwendungen betrifft, aber diese Lösung betrifft nur Powershell.
Christian Mikkelsen
Nach der Implementierung von "OnlyUseLatestCLR" ist mein Fiddler kaputt gegangen, und einige Powershell-Skripte wurden nicht mehr ausgeführt, da bestimmte Server nicht kontaktiert werden konnten. Ich habe die Werte im regedt32 manuell auf 0 zurückgesetzt und jetzt funktioniert alles wieder. Vielen Dank!
Neville
Was sind WASP, PSCX und SCOM (in diesem Zusammenhang)?
Peter Mortensen
7

Wenn Sie die Registrierungs- oder app.config-Dateien nicht ändern möchten, können Sie alternativ eine einfache .NET 4-Konsolen-App erstellen, die die Funktionen von PowerShell.exe nachahmt und die PowerShell ConsoleShell hostet.

Siehe Option 2 - Hosten von Windows PowerShell selbst

Fügen Sie zunächst einen Verweis auf die Assemblys System.Management.Automation und Microsoft.PowerShell.ConsoleHost hinzu, die sich unter % programfiles% \ Reference Assemblies \ Microsoft \ WindowsPowerShell \ v1.0 befinden

Verwenden Sie dann den folgenden Code:

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
quelle
6

Genau wie eine andere Option enthält die neueste PoshConsole- Version Binärdateien für .NET 4 RC (die gegen die RTM-Version problemlos funktionieren) ohne Konfiguration.

Jaykul
quelle
1

Führen Sie einfach Powershell.exe mit der COMPLUS_versionUmgebungsvariablen auf aus v4.0.30319. Zum Beispiel aus cmd.exe oder .bat-Datei:

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