Come posso eseguire PowerShell con .NET 4 runtime?

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 PowerShell viene eseguito), ma ora ha bisogno di lavorare con .NET 4 assembly e con .NET 2 assembly.

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

Come posso eseguire PowerShell con .NET 4 runtime?

PowerShell (il motore) funziona correttamente con .NET 4.0. PowerShell (l’host della console e l’ ISE ) non lo fanno, semplicemente perché sono stati compilati rispetto alle versioni precedenti di .NET. C’è un’impostazione del Registro di sistema 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 l’ISE per utilizzare .NET 4.0, è ansible modificare il file di configurazione ($ psHome \ powershell_ise.exe.config) per avere un blocco come questo:

       

È ansible creare applicazioni .NET 4.0 che chiamano PowerShell utilizzando l’API PowerShell (System.Management.Automation.PowerShell), ma questi passaggi aiuteranno a far funzionare gli host PowerShell in-core in .NET 4.0.


Rimuovi le chiavi di registro quando non ne hai più bisogno. Sono chiavi a livello di macchina e migrano forzatamente TUTTE le applicazioni a .NET 4.0, anche le applicazioni che utilizzano .net 2 e .net 3.5


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

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

        

Note aggiuntive sull’impostazione rapida:

Posizioni e file sono in qualche modo dipendenti dalla piattaforma; tuttavia ti fornirà una sintesi di come far funzionare la soluzione per te.

  • Puoi trovare la posizione di PowerShell sul tuo computer eseguendo cd $pshome nella finestra di Powershell (non funziona dal prompt di DOS).
    • Il percorso sarà simile a (esempio) C:\Windows\System32\WindowsPowerShell\v1.0\
  • Il nome file per inserire la configurazione è: powershell.exe.config se il tuo PowerShell.exe è in esecuzione (creare il file di configurazione se necessario).
    • Se PowerShellISE.Exe è in esecuzione, è necessario creare il suo file di configurazione complementare come PowerShellISE.Exe.config

Si prega di essere MOLTO attenti con l’utilizzo dell’approccio 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 aiuto di prova e non un meccanismo di qualità della produzione. Visual Studio 2008 e 2010, MSBuild , turbotax e una miriade di siti Web, SharePoint e così via non dovrebbero essere automatizzati.

Se è necessario utilizzare PowerShell con 4.0, questa operazione deve essere eseguita in base all’applicazione con un file di configurazione, è necessario verificare con il team PowerShell la raccomandazione precisa. È probabile che questo interrompa alcuni comandi PowerShell esistenti.

Se hai solo bisogno di eseguire un singolo comando, blocco di script o file di script in .NET 4, prova a utilizzare i file di configurazione di triggerszione di .NET 4 per avviare solo una singola istanza di PowerShell utilizzando la versione 4 di CLR.

Tutti i dettagli:

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

Un esempio di modulo PowerShell:

https://gist.github.com/882528

Ecco il contenuto del file di configurazione che ho usato per supportare entrambi gli assembly .NET 2.0 e .NET 4:

         

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

 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 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, iniettiamo anche un’istruzione trap nello script per visualizzare ulteriori informazioni diagnostiche (simile alla funzione Resolve-Error di Jeffrey Snover).

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

Crea un powershell4.cmd da qualche parte sul 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.^ > %~dp0powershell.exe.activation_config echo.^ >> %~dp0powershell.exe.activation_config echo. ^ >> %~dp0powershell.exe.activation_config echo. ^ >> %~dp0powershell.exe.activation_config echo. ^ >> %~dp0powershell.exe.activation_config echo.^ >> %~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 di 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 

Le altre risposte risalgono a prima del 2012 e si concentrano su “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 è l’ installazione della versione più recente di PowerShell . Verrà automaticamente indirizzato a CLR v4.0.30319 . Questo significa .NET 4.0, 4.5, 4.5.1, 4.5.2 o 4.6 (previsto per il 2015) poiché tutte queste versioni sono sostituzioni locali. Utilizzare $PSVersionTable o vedere Determinare il thread della versione di PowerShell installato se non si è sicuri della versione di PowerShell.

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

In realtà, PowerShell può essere eseguito utilizzando .NET 4 senza influire su altre applicazioni .NET. Avevo bisogno di farlo per utilizzare la nuova proprietà “Host” di HttpWebRequest, tuttavia la modifica di “OnlyUseLatestCLR” interrompeva Fiddler in quanto non poteva essere utilizzato su .NET 4.

Ovviamente gli sviluppatori di PowerShell hanno previsto che ciò accada e hanno aggiunto una chiave di registro per specificare quale versione del Framework dovrebbe utilizzare. Un piccolo problema è che è necessario assumere la proprietà della chiave di registro prima di cambiarla, 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 macchina a 64 bit)

Cambia il valore di quella chiave nella versione richiesta. Tieni presente che alcuni snap-in potrebbero non caricarsi più a meno che non siano compatibili con .NET 4. (WASP è l’unico con cui ho avuto problemi, ma non lo uso comunque). VMware , SQL Server 2008 , PSCX, Active Directory (Microsoft e Quest Software ) e SCOM funzionano tutti bene.

Se non si desidera modificare i file di registro o app.config, in alternativa è ansible creare una semplice app per console .NET 4 che riproduca ciò che PowerShell.exe esegue e ospita PowerShell ConsoleShell.

Vedere l’ opzione 2 – Hosting di Windows PowerShell

Innanzitutto, aggiungi un riferimento agli assembly System.Management.Automation e Microsoft.PowerShell.ConsoleHost che possono essere trovati in % programfiles% \ Reference Assemblies \ 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 ); } } } 

Proprio come un’altra opzione, l’ultima versione di PoshConsole include binari indirizzati a .NET 4 RC (che funzionano bene contro la versione RTM) senza alcuna configurazione.