Come posso eseguire PowerShell con il runtime .NET 4?


234

Sto aggiornando uno script PowerShell che gestisce alcuni assembly .NET. Lo script è stato scritto per gli assembly creati su .NET 2 (la stessa versione del framework con cui è in esecuzione PowerShell), ma ora deve funzionare con gli assembly .NET 4 e .NET 2.

Poiché .NET 4 supporta l'esecuzione di applicazioni basate su versioni precedenti del framework, sembra che la soluzione più semplice sia avviare PowerShell con il runtime .NET 4 quando devo eseguirlo su assembly .NET 4.

Come posso eseguire PowerShell con il runtime .NET 4?



8
In questi giorni la soluzione più semplice sarebbe quella di installare il CTP Powershell 3.0 che utilizza CLRVersion: 4.0.30319.1.
Jon Z

2
Chiunque sia ancora bloccato con PowerShell 2, vedere la risposta di Tim Lewis per una soluzione localizzata che non richiede la modifica di alcuna configurazione a livello di macchina.
Eric Eskildsen,

1
Per una soluzione non sistemica e senza file vedere questa risposta
vkrzv,

Risposte:


147

PowerShell (il motore) funziona correttamente con .NET 4.0. PowerShell (l'host della console e ISE ) no, semplicemente perché sono stati compilati con versioni precedenti di .NET. C'è un'impostazione del registro che cambierà il framework .NET caricato a livello di sistema , che a sua volta consentirà a PowerShell di utilizzare le classi .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

Per aggiornare solo ISE per utilizzare .NET 4.0, è possibile modificare il file di configurazione ($ psHome \ powershell_ise.exe.config) in modo che abbia un blocco come questo:

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

È possibile creare applicazioni .NET 4.0 che chiamano PowerShell usando l'API PowerShell (System.Management.Automation.PowerShell) bene, ma questi passaggi aiuteranno gli host PowerShell integrati a funzionare in .NET 4.0.


Rimuovere le chiavi del Registro di sistema quando non sono più necessarie. Queste sono chiavi a livello di macchina e migrano forzatamente TUTTE le applicazioni su .NET 4.0, anche le applicazioni che utilizzano .net 2 e .net 3.5



9
Per essere chiari, powershell.exe (l'app host della console) è un'applicazione nativa, non gestita.
Keith Hill,

4
Ho capito il mio problema dall'alto. È necessario inserire il file di configurazione nella directory a 64 bit durante l'esecuzione su un sistema operativo a 64 bit. L'eseguibile PowerShell a 32 bit sembra rilevare bene la modifica da lì.
Chris McKenzie,

11
Solo un piccolo consiglio. Rimuovere le chiavi del Registro di sistema quando non sono più necessarie. Ho appena perso un sacco di tempo cercando di scoprire perché non riuscivo a costruire un progetto .NET 3.5 a cui sto lavorando.
Klark,

7
La soluzione di modifica del registro proposta ha effetti collaterali spiacevoli se si esegue il multi-targeting (ovvero la scrittura di app .NET 2.0 in VS2010). Attenzione.
Todd Sprang,

9
Si noti che Microsoft mette in guardia dal fare ciò: "Sebbene sia possibile forzare l'esecuzione di PowerShell 2.0 con .NET Framework 4.0 utilizzando vari meccanismi come la creazione di un file di configurazione per PowerShell o la modifica del registro, questi meccanismi non sono supportati e possono avere effetti collaterali negativi su altre funzionalità di PowerShell come remoti di PowerShell e cmdlet con assembly in modalità mista. " connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 ha il supporto nativo per .NET 4.0.
Timbo,

238

La migliore soluzione che ho trovato è nel post sul blog Utilizzo delle versioni più recenti di .NET con PowerShell . Ciò consente l'esecuzione di powershell.exe con assembly .NET 4.

Basta modificare (o creare) in $pshome\powershell.exe.configmodo che contenga quanto segue:

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

Note aggiuntive sulla configurazione rapida:

Posizioni e file dipendono in qualche modo dalla piattaforma; tuttavia ti fornirà un'idea in linea di come far funzionare la soluzione per te.

  • È possibile trovare la posizione di PowerShell sul computer eseguendo cd $pshome nella finestra Powershell (non funziona dal prompt di DOS).
    • Path sarà qualcosa di simile (esempio) C:\Windows\System32\WindowsPowerShell\v1.0\
  • Il nome del file in cui inserire la configurazione è: powershell.exe.configse il tuo PowerShell.exeè in esecuzione (crea il file di configurazione se necessario).
    • Se PowerShellISE.Exeè in esecuzione, è necessario creare il file di configurazione associato comePowerShellISE.Exe.config

23
Sicuramente il modo corretto di farlo. Questo altera solo il comportamento di Powershell, non tutte le altre app .NET sul tuo computer ...
Erik A. Brandstadmoen

4
Funziona bene ma influisce su tutta la tua PowerShell. Se si desidera solo alcune delle funzionalità, creare una copia della cartella PowerShell e quindi modificare il file lì.
Matt,

8
Ho aggiunto un file come indicato sopra. Tuttavia, non riesco più a eseguire PowerShell con quel file presente. Viene visualizzato l'errore "Il volume di un file è stato modificato esternamente in modo che il file aperto non sia più valido." Qualche idea?
JoshL,

13
@JoshL - su un sistema a 64 bit, ho trovato .exe.config deve andare in SysWOW64 \ WindowsPowershell (la cartella a 32 bit), anche se stai cercando di eseguire PowerShell a 64 bit. Altrimenti viene visualizzato l'errore "alterato esternamente".
Sam,

4
Il powershell.exe.config deve trovarsi in due posizioni .... C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ e C: \ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome Reinstate Monica

28

Si prega di essere MOLTO attenti a utilizzare l'approccio con chiave di registro. Queste sono chiavi a livello di macchina e migrano forzatamente TUTTE le applicazioni su .NET 4.0.

Molti prodotti non funzionano se migrati forzatamente e questo è un ausilio per i test e non un meccanismo di qualità della produzione. Visual Studio 2008 e 2010, MSBuild , turbotax e una serie di siti Web, SharePoint e così via non dovrebbero essere automatizzati.

Se è necessario utilizzare PowerShell con 4.0, questo dovrebbe essere fatto in base all'applicazione con un file di configurazione, è necessario verificare con il team di PowerShell il consiglio preciso. È probabile che ciò rompa alcuni comandi di PowerShell esistenti.


Ottimo punto sull'uso della chiave di registro. Fortunatamente, l'applicazione di avvio con il file di configurazione funziona bene. I nostri script utilizzano principalmente i comandi del file system e le chiamate .NET dirette e non abbiamo riscontrato alcun problema con i comandi non funzionanti. Poiché .NET 4 è in gran parte compatibile con le versioni precedenti di .NET 2.0, non riterrei probabile che ci sarebbero molti comandi rotti (anche se non guasta mai essere prudenti :).
Imperatore XLII,


21

Se sei ancora bloccato su PowerShell v1.0 o v2.0, ecco la mia variazione sulla risposta eccellente di Jason Stangroome.

Crea un punto powershell4.cmdnel tuo percorso con i seguenti contenuti:

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

Ciò consentirà di avviare un'istanza della console PowerShell in esecuzione in .NET 4.0.

Puoi vedere la differenza sul mio sistema in cui ho PowerShell 2.0 esaminando l'output dei seguenti due comandi eseguiti da 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

3
Questa è di gran lunga la risposta migliore in quanto è una modifica molto localizzata e non esegue alcuna modifica persistente al sistema. Roba buona!
Sebastian,

fantastico! Potete aiutarmi qui? stackoverflow.com/questions/39801315/...
Johny perché

@TimLewis, è possibile inviare più istruzioni alla stessa istanza ps4.cmd?
johny perché

@johnywhy, inviare più istruzioni a .cmd equivale a inviare più istruzioni a .exe perché .cmd usa% * per passare tutti i suoi parametri a .exe. Non fa alcuna differenza, tuttavia, poiché è ancora necessario fare attenzione a come cmd.exe analizza la riga di comando quando passa i parametri all'eseguibile che sta avviando. Daremo un'occhiata alla tua altra domanda di overflow dello stack e tratterò i dettagli lì.
Tim Lewis,

Ho provato a usare questa tecnica in combinazione con il parametro della riga di comando -Version docs.microsoft.com/en-us/powershell/scripting/core-powershell/… Purtroppo, non funziona; viene invece lanciata la mia ultima versione di PowerShell (5.1.17134.407), determinata da $ PSVersionTable.PSVersion.
eisenpony,

17

Ecco il contenuto del file di configurazione che ho usato per supportare gli assembly .NET 2.0 e .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>

Inoltre, ecco una versione semplificata del codice compatibile con PowerShell 1.0 che ho usato per eseguire i nostri script dagli argomenti passati nella riga di comando:

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

Oltre alla gestione degli errori di base mostrata sopra, inseriamo anche trapun'istruzione nello script per visualizzare informazioni diagnostiche aggiuntive (simile alla funzione di risoluzione dell'errore di Jeffrey Snover ).


10

Le altre risposte risalgono a prima del 2012 e si concentrano sull'hacking di PowerShell 1.0 o PowerShell 2.0 per il targeting delle versioni più recenti di .NET Framework e Common Language Runtime (CLR).

Tuttavia, come è stato scritto in molti commenti, dal 2012 (quando è arrivato PowerShell 3.0) una soluzione molto migliore è installare la versione più recente di PowerShell . Mirerà automaticamente al CLR v4.0.30319. Ciò significa che .NET 4.0, 4.5, 4.5.1, 4.5.2 o 4.6 (previsto nel 2015) poiché tutte queste versioni sono sostituite sul posto l'una dall'altra. Utilizzare $PSVersionTableo consultare il thread Determinare la versione di PowerShell installata se non si è sicuri della propria versione di PowerShell.

Al momento in cui scrivo, la versione più recente di PowerShell è 4.0 e può essere scaricata con Windows Management Framework (link di ricerca di Google) .


2
I requisiti di sistema per Windows Management Framework 4.0 (sono simili per 3.0) sono: Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.
Peter Mortensen,

9

In realtà, puoi far funzionare PowerShell usando .NET 4 senza influire su altre applicazioni .NET. Ho dovuto farlo per utilizzare la nuova proprietà "Host" di HttpWebRequest, tuttavia modificando "OnlyUseLatestCLR" si è rotto Fiddler in quanto non poteva essere utilizzato in .NET 4.

Gli sviluppatori di PowerShell hanno ovviamente previsto che ciò accadesse e hanno aggiunto una chiave di registro per specificare quale versione del Framework dovrebbe usare. Un piccolo problema è che è necessario assumere la proprietà della chiave di registro prima di modificarla, poiché anche gli amministratori non hanno accesso.

  • HKLM: \ Software \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (64 bit e 32 bit)
  • HKLM: \ Software \ Wow6432Node \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (32 bit su computer a 64 bit)

Modificare il valore di quella chiave sulla versione richiesta. Tieni presente, tuttavia, che alcuni snapin potrebbero non caricarsi più a meno che non siano compatibili con .NET 4 (WASP è l'unico con cui ho avuto problemi, ma in realtà non lo uso comunque). VMWare , SQL Server 2008 , PSCX, Active Directory (Microsoft e Quest Software ) e SCOM funzionano tutti bene.


+1 Questa è un'alternativa molto importante (e migliore) rispetto all'altra voce di registro che interesserà tutte le applicazioni .net, ma questa soluzione riguarda solo PowerShell.
Christian Mikkelsen,

Dopo aver implementato "OnlyUseLatestCLR", il mio Fiddler si è rotto e alcuni script PowerShell non sono più in esecuzione perché non sono in grado di contattare determinati server. Ho modificato manualmente i valori su 0 nel regedt32, e ora tutto funziona di nuovo. Grazie!
Neville,

Cosa sono WASP, PSCX e SCOM (in questo contesto)?
Peter Mortensen,

7

Se non si desidera modificare il file di registro o i file app.config, un modo alternativo è quello di creare una semplice app console .NET 4 che imita ciò che fa PowerShell.exe e ospita PowerShell ConsoleShell.

Vedi l' opzione 2 - Hosting Windows PowerShell da solo

Innanzitutto, aggiungere un riferimento agli assiemi System.Management.Automation e Microsoft.PowerShell.ConsoleHost che si trovano in % programfiles% \ Reference Assembly \ Microsoft \ WindowsPowerShell \ v1.0

Quindi utilizzare il seguente codice:

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

6

Proprio come un'altra opzione, l'ultima versione di PoshConsole include file binari destinati a .NET 4 RC (che funzionano perfettamente con la versione RTM) senza alcuna configurazione.


1

Esegui powershell.exe con COMPLUS_versionla variabile di ambiente impostata su v4.0.30319. Ad esempio, da cmd.exe o .bat-file:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.