Jak mogę uruchomić PowerShell z środowiskiem uruchomieniowym .NET 4?

234

Aktualizuję skrypt PowerShell, który zarządza niektórymi zestawami .NET. Skrypt został napisany dla zestawów zbudowanych w oparciu o .NET 2 (ta sama wersja frameworku, z którym działa PowerShell), ale teraz musi współpracować z zestawami .NET 4, jak również z zestawami .NET 2.

Ponieważ .NET 4 obsługuje uruchomione aplikacje zbudowane na starszych wersjach frameworka, wydaje się, że najprostszym rozwiązaniem jest uruchomienie PowerShell z środowiskiem uruchomieniowym .NET 4, kiedy muszę uruchomić go na zestawach .NET 4.

Jak mogę uruchomić PowerShell z środowiskiem uruchomieniowym .NET 4?

Cesarz XLII
źródło
Duplikat stackoverflow.com/questions/1940983/... .
Jeremy McGee,
8
Obecnie najłatwiejszym rozwiązaniem byłoby zainstalowanie Powershell 3.0 CTP, który korzysta z CLRVersion: 4.0.30319.1.
jon Z
2
Każdy, kto nadal ma problemy z programem PowerShell 2, zapoznaj się z odpowiedzią Tima Lewisa na zlokalizowane rozwiązanie, które nie wymaga edytowania konfiguracji na całym komputerze.
Eric Eskildsen
1
Aby uzyskać niesystemowe i bezplikowe rozwiązanie, zobacz tę odpowiedź
vkrzv

Odpowiedzi:

147

PowerShell (silnik) działa dobrze w .NET 4.0. PowerShell (host konsoli i ISE ) nie, po prostu dlatego, że zostały skompilowane ze starszymi wersjami .NET. Istnieje ustawienie rejestru, które zmieni platformę .NET ładowaną ogólnosystemowo , co z kolei pozwoli PowerShellowi na użycie klas .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

Aby zaktualizować tylko ISE do korzystania z .NET 4.0, możesz zmienić plik konfiguracyjny ($ psHome \ powershell_ise.exe.config), aby mieć taki fragment:

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

Możesz budować aplikacje .NET 4.0, które wywołują PowerShell przy użyciu API PowerShell (System.Management.Automation.PowerShell), ale te kroki pomogą w uruchomieniu gotowych hostów PowerShell w .NET 4.0.


Usuń klucze rejestru, gdy już ich nie potrzebujesz. Są to klucze dla całej maszyny i wymuszają migrację WSZYSTKICH aplikacji do .NET 4.0, nawet aplikacji używających .net 2 i .net 3.5


Rozpocznij automatyzację
źródło
9
Dla jasności, powershell.exe (aplikacja hosta konsoli) jest aplikacją natywną - nie jest zarządzana.
Keith Hill,
4
Z góry zorientowałem się, jaki mam problem. W przypadku 64-bitowego systemu operacyjnego plik konfiguracyjny należy umieścić w 64-bitowym katalogu. Wydaje się, że 32-bitowy plik wykonywalny PowerShell doskonale odbiera zmiany.
Chris McKenzie
11
Tylko jedna mała rada. Usuń klucze rejestru, gdy już ich nie potrzebujesz. Właśnie straciłem mnóstwo czasu, próbując dowiedzieć się, dlaczego nie udało mi się zbudować projektu .NET 3.5, nad którym pracuję.
Klark,
7
Proponowane rozwiązanie modyfikacji rejestru ma nieprzyjemne skutki uboczne, jeśli robisz wiele celów (np. Piszesz aplikacje .NET 2.0 w VS2010). Strzec się.
Todd Sprang
9
Pamiętaj, że Microsoft ostrzega przed zrobieniem tego: „Możliwe jest wymuszenie działania programu PowerShell 2.0 z .NET Framework 4.0 przy użyciu różnych mechanizmów, takich jak tworzenie pliku konfiguracyjnego dla programu PowerShell lub edytowanie rejestru, jednak mechanizmy te nie są obsługiwane i mogą mieć negatywne skutki uboczne dla innych funkcji PowerShell, takich jak zdalne sterowanie PowerShell i polecenia cmdlet ze złożeniami w trybie mieszanym. ” connect.microsoft.com/PowerShell/feedback/details/525435/... Program Powershell 3.0 ma natywne wsparcie dla .NET 4.0.
Timbo
238

Najlepsze rozwiązanie, jakie znalazłem, znajduje się w poście na blogu Korzystanie z nowszych wersji platformy .NET z programem PowerShell . Dzięki temu powershell.exe może działać z zestawami .NET 4.

Po prostu zmodyfikuj (lub utwórz), $pshome\powershell.exe.configaby zawierał następujące elementy:

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

Dodatkowe uwagi na temat szybkiej konfiguracji:

Lokalizacje i pliki są nieco zależne od platformy; da ci jednak ogólny zarys tego, jak sprawić, by rozwiązanie działało dla Ciebie.

  • Możesz znaleźć lokalizację PowerShell na swoim komputerze, wykonując cd $pshome w oknie PowerShell (nie działa z wiersza poleceń DOS).
    • Ścieżka będzie jak (przykład) C:\Windows\System32\WindowsPowerShell\v1.0\
  • Nazwa pliku, w którym ma zostać wprowadzona konfiguracja to: powershell.exe.configjeśli PowerShell.exejest wykonywany (w razie potrzeby utwórz plik konfiguracyjny).
    • Jeśli PowerShellISE.Exejest uruchomiony, musisz utworzyć jego towarzyszący plik konfiguracyjny jakoPowerShellISE.Exe.config
cmo999
źródło
23
Zdecydowanie właściwy sposób na zrobienie tego. To zmienia tylko zachowanie Powershell, a nie każdą inną aplikację .NET na twoim komputerze ...
Erik A. Brandstadmoen
4
Działa to dobrze, ale wpływa na wszystkie twoje PowerShell. Jeśli chcesz tylko niektóre funkcje, zrób kopię folderu PowerShell, a następnie edytuj tam plik.
Matt
8
Dodałem plik jak wspomniano powyżej. Jednak nie mogę już uruchomić programu PowerShell z tym plikiem - pojawia się błąd „Wolumin dla pliku został zmieniony zewnętrznie, więc otwarty plik nie jest już prawidłowy”. Jakieś pomysły?
JoshL
13
@JoshL - w 64-bitowym systemie znalazłem plik .exe.config, aby przejść do SysWOW64 \ WindowsPowershell (32-bitowy folder), nawet jeśli próbujesz uruchomić 64-bitowy PowerShell. W przeciwnym razie pojawia się błąd „zmieniony zewnętrznie”.
Sam
4
Plik powershell.exe.config musi znajdować się w dwóch miejscach .... C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ i C: \ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome Przywróć Monikę
28

Należy BARDZO ostrożnie stosować metodę klucza rejestru. Są to klucze dla całej maszyny i wymuszają migrację WSZYSTKICH aplikacji do .NET 4.0.

Wiele produktów nie działa w przypadku przymusowej migracji, co jest pomocą testową, a nie mechanizmem jakości produkcji. Visual Studio 2008 i 2010, MSBuild , turbotax oraz wiele stron internetowych, SharePoint i tak dalej nie powinny być migrowane automatycznie.

Jeśli chcesz używać programu PowerShell z wersją 4.0, należy to zrobić dla każdej aplikacji za pomocą pliku konfiguracyjnego, należy to sprawdzić w zespole programu PowerShell w sprawie dokładnych zaleceń. Może to spowodować uszkodzenie niektórych istniejących poleceń PowerShell.

Madhu Talluri
źródło
Bardzo dobra uwaga na temat używania klucza rejestru. Na szczęście aplikacja uruchamiająca z plikiem konfiguracyjnym działa dobrze. Nasze skrypty używają przede wszystkim poleceń systemu plików i bezpośrednich wywołań .NET. Nie zauważyliśmy żadnych problemów z uszkodzonymi poleceniami. Ponieważ .NET 4 jest w dużej mierze wstecznie kompatybilny z .NET 2.0, nie sądzę, aby było prawdopodobne, że pojawi się wiele zepsutych poleceń (chociaż nigdy nie boli to przestroga :).
Cesarz XLII
21

Jeśli nadal tkwisz w programie PowerShell v1.0 lub v2.0, oto moja odmiana doskonałej odpowiedzi Jasona Stangroome'a.

Utwórz powershell4.cmdgdzieś na swojej ścieżce z następującą zawartością:

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

Umożliwi to uruchomienie instancji konsoli PowerShell działającej pod .NET 4.0.

Możesz zobaczyć różnicę w moim systemie, w którym mam PowerShell 2.0, sprawdzając dane wyjściowe następujących dwóch poleceń uruchamianych z 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
źródło
3
Jest to zdecydowanie najlepsza odpowiedź, ponieważ jest to bardzo zlokalizowana zmiana i nie powoduje ona ciągłych zmian w systemie. Dobry towar!
Sebastian
fantastyczny! Czy możesz mi pomóc tutaj? stackoverflow.com/questions/39801315/…
John, dlaczego
@TimLewis, czy można wysłać wiele instrukcji do tej samej instancji ps4.cmd?
John, dlaczego
@ johnywhy, wysyłanie wielu instrukcji do .cmd jest tym samym, co wysyłanie wielu instrukcji do .exe, ponieważ .cmd używa% * do przekazania wszystkich swoich parametrów do .exe. Nie robi to jednak różnicy, ponieważ nadal musisz uważać na to, jak cmd.exe analizuje wiersz poleceń, gdy przekazuje parametry do uruchamianego pliku wykonywalnego. Rzucę okiem na twoje inne pytanie dotyczące przepełnienia stosu i opiszę tam szczegóły.
Tim Lewis
Próbowałem użyć tej techniki w połączeniu z parametrem wiersza polecenia -Version docs.microsoft.com/en-us/powershell/scripting/core-powershell/... Niestety, to nie działa; zamiast tego uruchomiona jest moja najnowsza wersja PowerShell (5.1.17134.407), określona na podstawie $ PSVersionTable.PSVersion.
eisenpony,
17

Oto zawartość pliku konfiguracyjnego, którego użyłem do obsługi zarówno zespołów .NET 2.0, jak i .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>

Ponadto, oto uproszczona wersja kodu kompatybilnego z PowerShell 1.0, którego użyłem do wykonania naszych skryptów z przekazanych argumentów wiersza poleceń:

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

Oprócz podstawowej obsługi błędów pokazanej powyżej, wstrzykujemy również trapskrypt do skryptu, aby wyświetlić dodatkowe informacje diagnostyczne (podobne do funkcji błędu rozwiązania Jeffreya Snovera ).

Cesarz XLII
źródło
10

Inne odpowiedzi pochodzą sprzed 2012 roku i koncentrują się na „hakowaniu” programu PowerShell 1.0 lub PowerShell 2.0 w celu atakowania nowszych wersji programu .NET Framework i Common Language Runtime (CLR).

Jednak, jak napisano w wielu komentarzach, od 2012 r. (Kiedy pojawiła się PowerShell 3.0) znacznie lepszym rozwiązaniem jest zainstalowanie najnowszej wersji PowerShell . Będzie automatycznie celować w CLR v4.0.30319. Oznacza to .NET 4.0, 4.5, 4.5.1, 4.5.2 lub 4.6 (oczekiwany w 2015 r.), Ponieważ wszystkie te wersje zastępują się nawzajem. Użyj $PSVersionTablelub zobacz Określenie zainstalowanego wątku wersji PowerShell jeśli nie jesteś pewien swojej wersji PowerShell.

W chwili pisania tego tekstu najnowszą wersją programu PowerShell jest 4.0 i można ją pobrać za pomocą Windows Management Framework (link wyszukiwania Google) .

Jeppe Stig Nielsen
źródło
2
Wymagania systemowe dla Windows Management Framework 4.0 (są podobne dla 3.0): Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.
Peter Mortensen
9

W rzeczywistości można uruchomić PowerShell przy użyciu .NET 4 bez wpływu na inne aplikacje .NET. Musiałem to zrobić, aby użyć nowej właściwości „Host” HttpWebRequest, jednak zmiana „OnlyUseLatestCLR” spowodowała uszkodzenie Fiddlera, ponieważ nie można jej było używać w .NET 4.

Programiści PowerShell oczywiście przewidzieli, że tak się stanie, i dodali klucz rejestru, aby określić, jakiej wersji środowiska powinien używać. Jednym drobnym problemem jest to, że musisz przejąć na własność klucz rejestru przed jego zmianą, ponieważ nawet administratorzy nie mają dostępu.

  • HKLM: \ Software \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (64-bitowy i 32-bitowy)
  • HKLM: \ Software \ Wow6432Node \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (32-bitowy na komputerze 64-bitowym)

Zmień wartość tego klucza na wymaganą wersję. Pamiętaj jednak, że niektóre przystawki mogą się nie ładować, chyba że są zgodne z platformą .NET 4 (tylko z WASP miałem problemy, ale i tak z niego nie korzystam). VMWare , SQL Server 2008 , PSCX, Active Directory (Microsoft i Quest Software ) oraz SCOM działają dobrze.

Justin Yancey
źródło
+1 Jest to bardzo ważna alternatywa (i lepsza) niż inny wpis reg, który wpłynie na wszystkie aplikacje .net, ale to rozwiązanie wpływa tylko na PowerShell.
Christian Mikkelsen
Po wdrożeniu „OnlyUseLatestCLR” mój Fiddler się zepsuł, a niektóre skrypty PowerShell nie działają już z powodu braku możliwości kontaktu z niektórymi serwerami. Ręcznie zmieniłem wartości z powrotem na 0 w regedt32 i teraz wszystko znów działa. Dzięki!
Neville
Co to są WASP, PSCX i SCOM (w tym kontekście)?
Peter Mortensen
7

Jeśli nie chcesz modyfikować plików rejestru lub app.config, alternatywnym sposobem jest utworzenie prostej aplikacji konsoli .NET 4, która naśladuje działanie programu PowerShell.exe i obsługuje konsolę PowerShell.

Zobacz opcję 2 - samodzielne hostowanie środowiska Windows PowerShell

Najpierw dodaj odwołanie do zestawów System.Management.Automation i Microsoft.PowerShell.ConsoleHost, które można znaleźć w folderze% programfiles% \ Reference Assemblies \ Microsoft \ WindowsPowerShell \ v1.0

Następnie użyj następującego kodu:

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
źródło
6

Jako kolejna opcja, najnowsza wersja PoshConsole zawiera pliki binarne ukierunkowane na .NET 4 RC (które działają dobrze w stosunku do wersji RTM) bez żadnej konfiguracji.

Jaykul
źródło
1

Wystarczy uruchomić powershell.exe ze COMPLUS_versionzmienną środowiskową ustawioną na v4.0.30319. Na przykład z pliku cmd.exe lub pliku bat:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
vkrzv
źródło