How can I run PowerShell with the .NET 4 runtime?
Asked Answered
S

11

237

I am updating a PowerShell script that manages some .NET assemblies. The script was written for assemblies built against .NET 2 (the same version of the framework that PowerShell runs with), but now needs to work with .NET 4 assemblies as well as .NET 2 assemblies.

Since .NET 4 supports running applications built against older versions of the framework, it seems like the simplest solution is to launch PowerShell with the .NET 4 runtime when I need to run it against .NET 4 assemblies.

How can I run PowerShell with the .NET 4 runtime?

Snowinsummer answered 19/1, 2010 at 15:44 Comment(4)
Duplicate of #1941483.Caspian
These days the easiest solution would be to install the Powershell 3.0 CTP which uses CLRVersion: 4.0.30319.1.Favien
Anyone still stuck with PowerShell 2, see Tim Lewis's answer for a localized solution that doesn't require editing any machine-wide config.Canonicate
For a non-systemwide and fileless solution see this answerDorset
G
147

PowerShell (the engine) runs fine under .NET 4.0. PowerShell (the console host and the ISE) do not, simply because they were compiled against older versions of .NET. There's a registry setting that will change the .NET framework loaded systemwide, which will in turn allow PowerShell to use .NET 4.0 classes:

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

To update just the ISE to use .NET 4.0, you can change the configuration ($psHome\powershell_ise.exe.config) file to have a chunk like this:

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

You can build .NET 4.0 applications that call PowerShell using the PowerShell API (System.Management.Automation.PowerShell) just fine, but these steps will help get the in-the-box PowerShell hosts to work under .NET 4.0.


Remove the registry keys when you don't need them any more. These are machine-wide keys and forcibly migrate ALL applications to .NET 4.0, even applications using .net 2 and .net 3.5


Greyback answered 19/1, 2010 at 20:43 Comment(13)
Just to be clear, powershell.exe (the console host app) itself is a native application - not managed.Permanence
The registry setting is working fine for now, though I think changing our launcher from a .bat script calling powershell.exe to a simple app using System.Management.Automation.PowerShell will be a better long-term solution.Snowinsummer
If you want ISE 32 and 64 bit both updated to support 4.0, add the above .config file to both the 'C:\windows\System32\WindowsPowerShell\v1.0' and 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0' folders. Also, note that the answer by 'Emperor XLII' below has a better config file to use.Viminal
When I add powershell.exe.config to the $pshome directory powershell refused to load. I get an error saying: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Any ideas? The volume for a file has been externally altered so that the opened file is no longer valid.Drafty
I figured out my problem from above. You have to put the config file in the 64-bit directory when running on a 64-bit OS. The 32-bit powershell executable seems to pick up the change just fine from there.Drafty
Just one small advice. Remove the registry keys when you don't need them any more. I just lost a ton of time trying to find out why I couldn't build some .NET 3.5 project I am working on.Toluol
The proposed registry modification solution has nasty side-effects if you're doing multi-targeting (i.e. writing .NET 2.0 apps in VS2010). Beware.Stertor
These registry settings can also cause the Web Management Service (used in IIS and critical for Web Deploy) to not start.Sivie
Note that Microsoft warns strongly against doing this: "While it is possible to force PowerShell 2.0 to run with .NET Framework 4.0 using various mechanisms such as creating a config file for PowerShell or editing the registry, these mechanisms aren't supported and can have negative side effects on other PowerShell functionality such as PowerShell remoting and cmdlets with mixed-mode assemblies." connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 has native support for .NET 4.0.Cabbala
This may be an acceptable way to do it as a user, but I'm seeing people trying to add the .config file from their application installers. Who knows how many things that would break!Psychophysics
I honestly suggest people trying to do this migrate to Powershell v3 or greater, which will be running under .NET 4.0Greyback
@Kiquenet The newer .NET 4.5, .NET 4.5.1, .NET 4.5.2 and .NET 4.6 (will come in 2015) are all in-place replacements of .NET 4.0. So you target those automatically if you targeted .NET 4.0 before, as soon as the relevant .NET Framework version is installed. The version number 4.0.30319 is still valid for .NET 4.5 and 4.6.Fountainhead
I ran into a problem running these two lines, it appears to cause problems with starting up Event Viewer afterwards, I get the error in Event Viewer "MMC has detected an error in a snap-in and will unload it"Foreleg
I
239

The best solution I have found is in the blog post Using Newer Version(s) of .NET with PowerShell. This allows powershell.exe to run with .NET 4 assemblies.

Simply modify (or create) $pshome\powershell.exe.config so that it contains the following:

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

Additional, quick setup notes:

Locations and files are somewhat platform dependent; however will give you an inline gist of how to make the solution work for you.

  • You can find PowerShell's location on your computer by executing cd $pshome in the Powershell window (doesn't work from DOS prompt).
    • Path will be something like (example) C:\Windows\System32\WindowsPowerShell\v1.0\
  • The filename to put configuration in is: powershell.exe.config if your PowerShell.exe is being executed (create the config file if need be).
    • If PowerShellISE.Exe is running then you need to create its companion config file as PowerShellISE.Exe.config
Impersonate answered 21/2, 2011 at 17:26 Comment(13)
Definitely the correct way to do it. This alters only the behavior of Powershell, not every other .NET app on your machine...Aborticide
This works well but affects all your PowerShell. If you want just some of the functionality make a copy of the powershell folder and then edit the file there.Catechism
I added a file as noted above. However, I can no longer run PowerShell with that file present - I get the error "The volume for a file has been externally altered so that the opened file is no longer valid." Any ideas?Aerification
You may also want to create a powershell_ise.exe.config file (with the same contents).Trencher
I've provided a link to this answer to people a couple of times, and have just added some quick setup notes to help expedite carrying it out.Pentose
@Aerification - on a 64 bit system, I've found the .exe.config needs to go into SysWOW64\WindowsPowershell (the 32 bit folder), even if you're trying to run 64 bit powershell. Otherwise you get the 'externally altered' error.Scup
I cannot access that folder, meaning that It is not possible for me to create or edit files, not even trying to create them on Desktop and then using the shell to copy them! Access Denied! (ps: I ran the shell by right-clicking on its link and choosing: "Start as Admin").Dallas
Has anyone seen this working on Windows 7 32 bits? I'm on a system that does not include .NET 3.5 (which is the requirement for ISE v2), and I've never been able to run ISE against .NET 4 using this trick.Medullated
Adding this config file gives me the following error in the Event Log: Activation context generation failed for "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe".Error in manifest or policy file "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe.Config" on line 0. Invalid Xml syntax.Imponderabilia
The powershell.exe.config needs to be in two places.... C:\Windows\System32\WindowsPowerShell\v1.0\ and C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Rittenhouse
In my case it was showing the files as 0 kb and to my surprise, when open in notepad they were blank. As soon as the powershell console was open, it was showing the above message "The volume of file.....". The solution was to open in Notepad and add the XML once again. Thanks Guys.Aculeus
Rather than affecting all your PowerShell, you can do a localized change as detailed here https://mcmap.net/q/101790/-how-can-i-run-powershell-with-the-net-4-runtime so that you can run it in v2 or v4 on demand.Delative
@Aerification The error happens if the config file is empty. With Powershell 64 bits, you need the config file in System32 (64-bit DLLs - the name is deceptive), and you need a 64-bit text editor to write there. If you create the config file in Windows Explorer, and use a 32 bit text editor, Windows automatically redirects you to SysWOW64 (32-bit DLLs) when you save, leaving the file in System32 empty. In my case, it's running fine with the config file only in System32 (.NET v4 on PS 64 bits and .NET v2 on PS 32 bits) or only in SysWOW64 (.NET v2 on PS 64 bits and .NET v4 on PS 32 bits).Deoxidize
G
147

PowerShell (the engine) runs fine under .NET 4.0. PowerShell (the console host and the ISE) do not, simply because they were compiled against older versions of .NET. There's a registry setting that will change the .NET framework loaded systemwide, which will in turn allow PowerShell to use .NET 4.0 classes:

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

To update just the ISE to use .NET 4.0, you can change the configuration ($psHome\powershell_ise.exe.config) file to have a chunk like this:

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

You can build .NET 4.0 applications that call PowerShell using the PowerShell API (System.Management.Automation.PowerShell) just fine, but these steps will help get the in-the-box PowerShell hosts to work under .NET 4.0.


Remove the registry keys when you don't need them any more. These are machine-wide keys and forcibly migrate ALL applications to .NET 4.0, even applications using .net 2 and .net 3.5


Greyback answered 19/1, 2010 at 20:43 Comment(13)
Just to be clear, powershell.exe (the console host app) itself is a native application - not managed.Permanence
The registry setting is working fine for now, though I think changing our launcher from a .bat script calling powershell.exe to a simple app using System.Management.Automation.PowerShell will be a better long-term solution.Snowinsummer
If you want ISE 32 and 64 bit both updated to support 4.0, add the above .config file to both the 'C:\windows\System32\WindowsPowerShell\v1.0' and 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0' folders. Also, note that the answer by 'Emperor XLII' below has a better config file to use.Viminal
When I add powershell.exe.config to the $pshome directory powershell refused to load. I get an error saying: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Any ideas? The volume for a file has been externally altered so that the opened file is no longer valid.Drafty
I figured out my problem from above. You have to put the config file in the 64-bit directory when running on a 64-bit OS. The 32-bit powershell executable seems to pick up the change just fine from there.Drafty
Just one small advice. Remove the registry keys when you don't need them any more. I just lost a ton of time trying to find out why I couldn't build some .NET 3.5 project I am working on.Toluol
The proposed registry modification solution has nasty side-effects if you're doing multi-targeting (i.e. writing .NET 2.0 apps in VS2010). Beware.Stertor
These registry settings can also cause the Web Management Service (used in IIS and critical for Web Deploy) to not start.Sivie
Note that Microsoft warns strongly against doing this: "While it is possible to force PowerShell 2.0 to run with .NET Framework 4.0 using various mechanisms such as creating a config file for PowerShell or editing the registry, these mechanisms aren't supported and can have negative side effects on other PowerShell functionality such as PowerShell remoting and cmdlets with mixed-mode assemblies." connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 has native support for .NET 4.0.Cabbala
This may be an acceptable way to do it as a user, but I'm seeing people trying to add the .config file from their application installers. Who knows how many things that would break!Psychophysics
I honestly suggest people trying to do this migrate to Powershell v3 or greater, which will be running under .NET 4.0Greyback
@Kiquenet The newer .NET 4.5, .NET 4.5.1, .NET 4.5.2 and .NET 4.6 (will come in 2015) are all in-place replacements of .NET 4.0. So you target those automatically if you targeted .NET 4.0 before, as soon as the relevant .NET Framework version is installed. The version number 4.0.30319 is still valid for .NET 4.5 and 4.6.Fountainhead
I ran into a problem running these two lines, it appears to cause problems with starting up Event Viewer afterwards, I get the error in Event Viewer "MMC has detected an error in a snap-in and will unload it"Foreleg
C
28

Please be VERY careful with using the registry key approach. These are machine-wide keys and forcibily migrate ALL applications to .NET 4.0.

Many products do not work if forcibily migrated and this is a testing aid and not a production quality mechanism. Visual Studio 2008 and 2010, MSBuild, turbotax, and a host of websites, SharePoint and so on should not be automigrated.

If you need to use PowerShell with 4.0, this should be done on a per-application basis with a configuration file, you should check with the PowerShell team on the precise recommendation. This is likely to break some existing PowerShell commands.

Chavey answered 10/6, 2010 at 21:26 Comment(1)
Very good point about using the registry key. Happily, the launcher application with config file is working just fine. Our scripts primarily use file system commands and direct .NET calls, and we have not noticed any problems with broken commands. Since .NET 4 is largely backward compatible with .NET 2.0, I would not think it likely that there would be many broken commands (though it never hurts to be cautions :).Snowinsummer
Z
26

If you only need to execute a single command, script block, or script file in .NET 4, try using Activation Configuration Files from .NET 4 to start only a single instance of PowerShell using version 4 of the CLR.

Full details:

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

An example PowerShell module:

https://gist.github.com/882528

Zygospore answered 23/3, 2011 at 9:39 Comment(0)
D
21

If you're still stuck on PowerShell v1.0 or v2.0, here is my variation on Jason Stangroome's excellent answer.

Create a powershell4.cmd somewhere on your path with the following contents:

@echo off
:: https://mcmap.net/q/22705/-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=

This will allow you to launch an instance of the powershell console running under .NET 4.0.

You can see the difference on my system where I have PowerShell 2.0 by examining the output of the following two commands run from 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
Delative answered 7/7, 2015 at 21:13 Comment(6)
This is by far the best answer since it is a very localised change and does not do any persistent changing to the system. Good stuff!Spoliation
fantastic! Can you help over here? #39801815Matterhorn
@TimLewis, is it possible to send multiple statements to the same ps4.cmd instance?Matterhorn
@johnywhy, sending multiple statements to the .cmd is the same as sending multiple statements to the .exe because the .cmd uses %* to pass all its parameters through to the .exe. It doesn't make a difference however since you still have to be careful with how cmd.exe parses the command line when it passes the parameters to the executable it is launching. I'll take a look at your other stack-overflow question and address specifics there.Delative
I tried to use this technique in combination with the -Version command line parameter learn.microsoft.com/en-us/powershell/scripting/core-powershell/… Sadly, it doesn't work; my latest version of PowerShell (5.1.17134.407), as determined from $PSVersionTable.PSVersion, is launched instead.Scarper
If using this in a .bat file, remember to add call before powershell4.cmd or else the script will quit immediately after running the command without any errors. I found that out from here. Also, saving the powershell4.cmd in a folder containing spaces does not seem to work.Carmel
S
17

Here is the contents of the configuration file I used to support both .NET 2.0 and .NET 4 assemblies:

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

Also, here’s a simplified version of the PowerShell 1.0 compatible code I used to execute our scripts from the passed in command line arguments:

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

In addition to the basic error handling shown above, we also inject a trap statement into the script to display additional diagnostic information (similar to Jeffrey Snover's Resolve-Error function).

Snowinsummer answered 8/3, 2010 at 20:46 Comment(0)
F
11

The other answers are from before 2012, and they focus on "hacking" PowerShell 1.0 or PowerShell 2.0 into targeting newer versions of the .NET Framework and Common Language Runtime (CLR).

However, as has been written in many comments, since 2012 (when PowerShell 3.0 came) a much better solution is to install the newest version of PowerShell. It will automatically target CLR v4.0.30319. This means .NET 4.0, 4.5, 4.5.1, 4.5.2, or 4.6 (expected in 2015) since all of these versions are in-place replacements of each other. Use $PSVersionTable or see the Determine installed PowerShell version thread if you are unsure of your PowerShell version. Edit: Also thread Which .NET version is my PowerShell script using?

At the time of writing, the newest version of PowerShell is 4.0, and it can be downloaded with the Windows Management Framework (Google search link).

Fountainhead answered 28/11, 2014 at 11:55 Comment(1)
The system requirements for the Windows Management Framework 4.0 (they are similar for 3.0) are: Windows 7, Windows Embedded Standard 7, Windows Server 2008 R2, Windows Server 2012.Niven
D
9

Actually, you can get PowerShell to run using .NET 4 without affecting other .NET applications. I needed to do so to use the new HttpWebRequest "Host" property, however changing the "OnlyUseLatestCLR" broke Fiddler as that could not be used under .NET 4.

The developers of PowerShell obviously foresaw this happening, and they added a registry key to specify what version of the Framework it should use. One slight issue is that you need to take ownership of the registry key before changing it, as even administrators do not have access.

  • HKLM:\Software\Microsoft\Powershell\1\PowerShellEngine\RuntimeVersion (64 bit and 32 bit)
  • HKLM:\Software\Wow6432Node\Microsoft\Powershell\1\PowerShellEngine\RuntimeVersion (32 bit on 64 bit machine)

Change the value of that key to the required version. Keep in mind though that some snapins may no longer load unless they are .NET 4 compatible (WASP is the only one I have had trouble with, but I don't really use it anyway). VMWare, SQL Server 2008, PSCX, Active Directory (Microsoft and Quest Software) and SCOM all work fine.

Daley answered 1/12, 2010 at 0:22 Comment(3)
+1 This is a very important alternative (and better) than the other reg entry which will affect all .net applications, but this solution only affects powershell.Mond
After implementing the "OnlyUseLatestCLR" my Fiddler broke as well as some powershell scripts not runnign anymore due to not being able to contact certain servers. I manually changed the values back to 0 in the regedt32, and now eveything working again. Thanks!Halimeda
What are WASP, PSCX, and SCOM (in this context)?Niven
B
7

If you don't want to modify the registry or app.config files, an alternate way is to create a simple .NET 4 console app that mimicks what PowerShell.exe does and hosts the PowerShell ConsoleShell.

See Option 2 – Hosting Windows PowerShell yourself

First, add a reference to the System.Management.Automation and Microsoft.PowerShell.ConsoleHost assemblies which can be found under %programfiles%\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0

Then use the following 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
            );
        }
    }
}
Birdwell answered 3/12, 2010 at 18:42 Comment(0)
P
6

Just as another option, the latest PoshConsole release includes binaries targeted to .NET 4 RC (which work fine against the RTM release) without any configuration.

Physician answered 22/4, 2010 at 4:40 Comment(0)
D
3

Just run powershell.exe with COMPLUS_version environment variable set to v4.0.30319. For example, from cmd.exe or .bat-file:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
Dorset answered 27/9, 2019 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.