¿Cómo puedo ejecutar PowerShell con .NET 4 runtime?

234

Estoy actualizando un script de PowerShell que administra algunos ensamblados .NET. El script se escribió para ensamblados creados con .NET 2 (la misma versión del marco con el que se ejecuta PowerShell), pero ahora debe funcionar con ensamblados .NET 4 y ensamblados .NET 2.

Dado que .NET 4 admite la ejecución de aplicaciones creadas en versiones anteriores del marco, parece que la solución más simple es iniciar PowerShell con el tiempo de ejecución de .NET 4 cuando necesito ejecutarlo en ensamblados de .NET 4.

¿Cómo puedo ejecutar PowerShell con .NET 4 runtime?

Emperador XLII
fuente
Duplicado de stackoverflow.com/questions/1940983/… .
Jeremy McGee
8
En estos días, la solución más fácil sería instalar el Powershell 3.0 CTP que utiliza CLRVersion: 4.0.30319.1.
Jon Z
2
Cualquier persona que todavía tenga problemas con PowerShell 2, vea la respuesta de Tim Lewis para una solución localizada que no requiere editar ninguna configuración de toda la máquina.
Eric Eskildsen
1
Para una solución que no sea de todo el sistema y sin archivos, vea esta respuesta
vkrzv,

Respuestas:

147

PowerShell (el motor) funciona bien en .NET 4.0. PowerShell (el host de la consola y el ISE ) no lo hacen, simplemente porque se compilaron con versiones anteriores de .NET. Hay una configuración de registro que cambiará el marco .NET cargado en todo el sistema , lo que a su vez permitirá que PowerShell use las clases .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

Para actualizar solo el ISE para usar .NET 4.0, puede cambiar el archivo de configuración ($ psHome \ powershell_ise.exe.config) para tener un fragmento como este:

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

Puede crear aplicaciones .NET 4.0 que llamen a PowerShell utilizando la API de PowerShell (System.Management.Automation.PowerShell) muy bien, pero estos pasos ayudarán a que los hosts PowerShell listos para usar funcionen bajo .NET 4.0.


Elimine las claves de registro cuando ya no las necesite. Estas son claves de toda la máquina y migran por la fuerza TODAS las aplicaciones a .NET 4.0, incluso las aplicaciones que usan .net 2 y .net 3.5


Comenzar a automatizar
fuente
99
Para ser claros, powershell.exe (la aplicación host de consola) en sí es una aplicación nativa, no administrada.
Keith Hill el
44
Descubrí mi problema desde arriba. Debe colocar el archivo de configuración en el directorio de 64 bits cuando se ejecuta en un sistema operativo de 64 bits. El ejecutable powershell de 32 bits parece recoger el cambio a partir de ahí.
Chris McKenzie
11
Solo un pequeño consejo. Elimine las claves de registro cuando ya no las necesite. Acabo de perder un montón de tiempo tratando de descubrir por qué no pude construir algún proyecto .NET 3.5 en el que estoy trabajando.
Klark
77
La solución de modificación de registro propuesta tiene efectos secundarios desagradables si está realizando una selección de objetivos múltiples (es decir, escribiendo aplicaciones .NET 2.0 en VS2010). Tener cuidado.
Todd Sprang
99
Tenga en cuenta que Microsoft advierte fuertemente contra hacer esto: "Si bien es posible forzar a PowerShell 2.0 a ejecutarse con .NET Framework 4.0 utilizando diversos mecanismos, como crear un archivo de configuración para PowerShell o editar el registro, estos mecanismos no son compatibles y pueden tener efectos secundarios negativos en otras funciones de PowerShell, como la comunicación remota de PowerShell y los cmdlets con ensamblajes de modo mixto ". connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 tiene soporte nativo para .NET 4.0.
Timbo
238

La mejor solución que he encontrado está en la publicación del blog Uso de versiones más recientes de .NET con PowerShell . Esto permite que powershell.exe se ejecute con ensamblados .NET 4.

Simplemente modifique (o cree) $pshome\powershell.exe.configpara que contenga lo siguiente:

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

Notas adicionales de configuración rápida:

Las ubicaciones y los archivos dependen de alguna manera de la plataforma; sin embargo, le dará una idea general de cómo hacer que la solución funcione para usted.

  • Puede encontrar la ubicación de PowerShell en su computadora ejecutando cd $pshome en la ventana de Powershell (no funciona desde el indicador de DOS).
    • El camino será algo como (ejemplo) C:\Windows\System32\WindowsPowerShell\v1.0\
  • El nombre de archivo para poner la configuración es: powershell.exe.configsi PowerShell.exese está ejecutando (cree el archivo de configuración si es necesario).
    • Si se PowerShellISE.Exeestá ejecutando, debe crear su archivo de configuración complementario comoPowerShellISE.Exe.config
cmo999
fuente
23
Definitivamente la forma correcta de hacerlo. Esto altera solo el comportamiento de Powershell, no todas las demás aplicaciones .NET en su máquina ...
Erik A. Brandstadmoen
44
Esto funciona bien pero afecta a todos sus PowerShell. Si solo desea algo de la funcionalidad, haga una copia de la carpeta powershell y luego edite el archivo allí.
Matt
8
Agregué un archivo como se señaló anteriormente. Sin embargo, ya no puedo ejecutar PowerShell con ese archivo presente: aparece el error "El volumen de un archivo se ha modificado externamente para que el archivo abierto ya no sea válido". ¿Algunas ideas?
JoshL
13
@JoshL: en un sistema de 64 bits, descubrí que .exe.config debe ir a SysWOW64 \ WindowsPowershell (la carpeta de 32 bits), incluso si está intentando ejecutar PowerShell de 64 bits. De lo contrario, aparece el error 'alterado externamente'.
Sam
44
El powershell.exe.config debe estar en dos lugares ... C: \ Windows \ System32 \ WindowsPowerShell \ v1.0 \ y C: \ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome Reinstate Monica
28

Tenga MUCHO cuidado al usar el enfoque de clave de registro. Estas son claves de toda la máquina y permiten migrar forzosamente TODAS las aplicaciones a .NET 4.0.

Muchos productos no funcionan si la migración migra por la fuerza y ​​esto es una ayuda de prueba y no un mecanismo de calidad de producción. Visual Studio 2008 y 2010, MSBuild , turbotax y una gran cantidad de sitios web, SharePoint , etc. no deben automatizarse.

Si necesita usar PowerShell con 4.0, esto debe hacerse por aplicación con un archivo de configuración, debe consultar con el equipo de PowerShell sobre la recomendación precisa. Es probable que esto rompa algunos comandos de PowerShell existentes.

Madhu Talluri
fuente
Muy buen punto sobre el uso de la clave de registro. Afortunadamente, la aplicación de inicio con el archivo de configuración funciona bien. Nuestros scripts utilizan principalmente comandos del sistema de archivos y llamadas directas a .NET, y no hemos notado ningún problema con los comandos rotos. Dado que .NET 4 es en gran medida compatible con versiones anteriores de .NET 2.0, no creo que sea probable que haya muchos comandos rotos (aunque nunca está de más tener precauciones :).
Emperador XLII
21

Si todavía está atascado en PowerShell v1.0 o v2.0, aquí está mi variación sobre la excelente respuesta de Jason Stangroome.

Crea un powershell4.cmdlugar en tu camino con los siguientes contenidos:

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

Esto le permitirá iniciar una instancia de la consola powershell que se ejecuta en .NET 4.0.

Puede ver la diferencia en mi sistema donde tengo PowerShell 2.0 al examinar la salida de los siguientes dos comandos que se ejecutan desde 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
fuente
3
Esta es, con mucho, la mejor respuesta, ya que es un cambio muy localizado y no hace ningún cambio persistente en el sistema. ¡Buen material!
Sebastian
¡fantástico! ¿Puedes ayudar por aquí? stackoverflow.com/questions/39801315/…
johny why
@TimLewis, ¿es posible enviar varias declaraciones a la misma instancia de ps4.cmd?
johny por qué el
@johnywhy, enviar múltiples declaraciones al .cmd es lo mismo que enviar múltiples declaraciones al .exe porque el .cmd usa% * para pasar todos sus parámetros al .exe. Sin embargo, no hace la diferencia, ya que aún debe tener cuidado con cómo cmd.exe analiza la línea de comandos cuando pasa los parámetros al ejecutable que está iniciando. Echaré un vistazo a su otra pregunta de desbordamiento de pila y abordaré los detalles allí.
Tim Lewis
Traté de usar esta técnica en combinación con el parámetro de línea de comando -Version docs.microsoft.com/en-us/powershell/scripting/core-powershell/… Lamentablemente, no funciona; en su lugar, se lanzó mi última versión de PowerShell (5.1.17134.407), según lo determinado por $ PSVersionTable.PSVersion.
eisenpony
17

Aquí está el contenido del archivo de configuración que utilicé para admitir los ensamblados .NET 2.0 y .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>

Además, aquí hay una versión simplificada del código compatible con PowerShell 1.0 que utilicé para ejecutar nuestros scripts a partir de los argumentos de la línea de comandos:

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

Además del manejo básico de errores que se muestra arriba, también inyectamos una trapdeclaración en el script para mostrar información de diagnóstico adicional (similar a la función Resolve-Error de Jeffrey Snover ).

Emperador XLII
fuente
10

Las otras respuestas son anteriores a 2012, y se centran en "piratear" PowerShell 1.0 o PowerShell 2.0 para apuntar a versiones más nuevas de .NET Framework y Common Language Runtime (CLR).

Sin embargo, como se ha escrito en muchos comentarios, desde 2012 (cuando llegó PowerShell 3.0) una solución mucho mejor es instalar la versión más reciente de PowerShell . Apuntará automáticamente a CLR v4.0.30319. Esto significa .NET 4.0, 4.5, 4.5.1, 4.5.2 o 4.6 (esperado en 2015) ya que todas estas versiones son reemplazos in situ entre sí. Utilice $PSVersionTableo vea el subproceso Determinar la versión instalada de PowerShell si no está seguro de su versión de PowerShell.

Al momento de escribir, la versión más nueva de PowerShell es 4.0, y se puede descargar con el Marco de administración de Windows (enlace de búsqueda de Google) .

Jeppe Stig Nielsen
fuente
2
Los requisitos del sistema para Windows Management Framework 4.0 (son similares para 3.0) son: Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.
Peter Mortensen
9

En realidad, puede hacer que PowerShell se ejecute usando .NET 4 sin afectar otras aplicaciones .NET. Necesitaba hacerlo para usar la nueva propiedad "Host" HttpWebRequest, sin embargo, cambiar el "OnlyUseLatestCLR" rompió Fiddler ya que no se podía usar en .NET 4.

Los desarrolladores de PowerShell obviamente previeron que esto sucedería, y agregaron una clave de registro para especificar qué versión del Framework debería usar. Un pequeño problema es que debe tomar posesión de la clave de registro antes de cambiarla, ya que incluso los administradores no tienen acceso.

  • HKLM: \ Software \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (64 bits y 32 bits)
  • HKLM: \ Software \ Wow6432Node \ Microsoft \ Powershell \ 1 \ PowerShellEngine \ RuntimeVersion (32 bits en una máquina de 64 bits)

Cambie el valor de esa clave a la versión requerida. Sin embargo, tenga en cuenta que algunos complementos ya no pueden cargarse a menos que sean compatibles con .NET 4 (WASP es el único con el que he tenido problemas, pero realmente no lo uso de todos modos). VMWare , SQL Server 2008 , PSCX, Active Directory (Microsoft y Quest Software ) y SCOM funcionan bien.

Justin Yancey
fuente
+1 Esta es una alternativa muy importante (y mejor) que la otra entrada de registro que afectará a todas las aplicaciones .net, pero esta solución solo afecta a powershell.
Christian Mikkelsen
Después de implementar "OnlyUseLatestCLR", mi Fiddler se rompió y algunos scripts de PowerShell ya no se ejecutan debido a que no puedo contactar con ciertos servidores. Cambié manualmente los valores a 0 en el regedt32, y ahora todo vuelve a funcionar. ¡Gracias!
Neville
¿Qué son WASP, PSCX y SCOM (en este contexto)?
Peter Mortensen
7

Si no desea modificar el registro o los archivos app.config, una forma alternativa es crear una aplicación de consola .NET 4 simple que imite lo que hace PowerShell.exe y aloja PowerShell ConsoleShell.

Consulte la Opción 2: Hospedaje de Windows PowerShell usted mismo

Primero, agregue una referencia a los ensamblados System.Management.Automation y Microsoft.PowerShell.ConsoleHost que se pueden encontrar en % programfiles% \ Reference Assemblies \ Microsoft \ WindowsPowerShell \ v1.0

Luego use el siguiente código:

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

Como otra opción, la última versión de PoshConsole incluye binarios dirigidos a .NET 4 RC (que funcionan bien con la versión RTM) sin ninguna configuración.

Jaykul
fuente
1

Simplemente ejecute powershell.exe con COMPLUS_versionla variable de entorno establecida en v4.0.30319. Por ejemplo, desde cmd.exe o .bat-file:

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