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?

Anthony Mastrean
  • 21,850
  • 21
  • 110
  • 188
Emperor XLII
  • 13,014
  • 11
  • 65
  • 75
  • Duplicate of http://stackoverflow.com/questions/1940983/loading-net-4-0-beta2-assembly-in-powershell-2-0. – Jeremy McGee Jan 19 '10 at 20:21
  • 8
    These days the easiest solution would be to install the Powershell 3.0 CTP which uses CLRVersion: 4.0.30319.1. – jon Z Nov 16 '11 at 12:13
  • 2
    **Anyone still stuck with PowerShell 2, [see Tim Lewis's answer](https://stackoverflow.com/a/31279372/1958726)** for a localized solution that doesn't require editing any machine-wide config. – Eric Eskildsen Jul 24 '17 at 12:20
  • 1
    For a non-systemwide and fileless solution see [this answer](https://stackoverflow.com/a/58131378/835103) – user10101 Sep 27 '19 at 09:14

11 Answers11

240

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
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
cmo999
  • 2,409
  • 1
  • 14
  • 2
  • 23
    Definitely the correct way to do it. This alters only the behavior of Powershell, not every other .NET app on your machine... – Erik A. Brandstadmoen Mar 11 '11 at 07:12
  • 4
    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. – Matt Aug 16 '11 at 16:45
  • 8
    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? – JoshL Oct 05 '11 at 18:36
  • 2
    You may also want to create a powershell_ise.exe.config file (with the same contents). – Matt Varblow Oct 06 '11 at 20:13
  • 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. – John K Nov 25 '11 at 16:07
  • 13
    @JoshL - 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. – Sam Dec 06 '11 at 02:43
  • 1
    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"). – Andry Oct 26 '12 at 23:04
  • 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. – Poorkenny Mar 04 '13 at 18:07
  • 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. – Nacht Sep 25 '13 at 04:54
  • 4
    The powershell.exe.config needs to be in two places.... C:\Windows\System32\WindowsPowerShell\v1.0\ and C:\Windows\SysWOW64\WindowsPowerShell\v1.0\ – Jonesome Reinstate Monica Jan 13 '15 at 20:12
  • 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. – Sanjay Zalke Jan 20 '15 at 10:55
  • Rather than affecting all your PowerShell, you can do a localized change as detailed here http://stackoverflow.com/a/31279372/67865 so that you can run it in v2 or v4 on demand. – Tim Lewis May 05 '16 at 10:36
  • @JoshL 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). – Narvarth May 03 '20 at 23:37
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


Iain
  • 6,392
  • 2
  • 30
  • 50
Start-Automating
  • 8,067
  • 2
  • 28
  • 47
  • 9
    Just to be clear, powershell.exe (the console host app) itself is a native application - not managed. – Keith Hill Jan 20 '10 at 01:43
  • 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. – Emperor XLII Jan 20 '10 at 15:26
  • 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. – scobi Jul 20 '10 at 19:37
  • 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. – Chris McKenzie Oct 31 '11 at 18:04
  • 4
    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. – Chris McKenzie Oct 31 '11 at 18:33
  • 11
    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. – Klark Dec 15 '11 at 14:15
  • 7
    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. – Todd Sprang Dec 16 '11 at 19:14
  • These registry settings can also cause the Web Management Service (used in IIS and critical for Web Deploy) to not start. – Mani Gandham Jun 26 '12 at 19:12
  • 9
    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." http://connect.microsoft.com/PowerShell/feedback/details/525435/net-4-0-assemblies-and-powershell-v2 Powershell 3.0 has native support for .NET 4.0. – Tim Sparkles Oct 17 '12 at 17:44
  • 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! – Nicolás Oct 08 '13 at 18:27
  • 1
    I honestly suggest people trying to do this migrate to Powershell v3 or greater, which will be running under .NET 4.0 – Start-Automating Oct 08 '13 at 22:13
  • 3
    @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. – Jeppe Stig Nielsen Nov 28 '14 at 10:34
  • 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" – PeskyGnat Mar 06 '15 at 14:49
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Madhu Talluri
  • 289
  • 3
  • 2
  • 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 :). – Emperor XLII Jun 11 '10 at 13:15
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

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
Jason Stangroome
  • 4,459
  • 3
  • 33
  • 39
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
:: 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=

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
Tim Lewis
  • 3,335
  • 1
  • 36
  • 26
  • 3
    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! – Sebastian Oct 30 '15 at 08:09
  • fantastic! Can you help over here? http://stackoverflow.com/questions/39801315/how-to-chain-commands-at-a-special-powershell-4-command-prompt – johny why Sep 30 '16 at 23:14
  • @TimLewis, is it possible to send multiple statements to the same ps4.cmd instance? – johny why Oct 02 '16 at 18:10
  • @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. – Tim Lewis Oct 03 '16 at 13:29
  • I tried to use this technique in combination with the -Version command line parameter https://learn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help?view=powershell-6#-version- Sadly, it doesn't work; my latest version of PowerShell (5.1.17134.407), as determined from $PSVersionTable.PSVersion, is launched instead. – eisenpony Dec 07 '18 at 20:06
  • 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](https://stackoverflow.com/questions/7320074/batch-file-stops-running-after-the-first-command#7320097). Also, saving the `powershell4.cmd` in a folder containing spaces does not seem to work. – htmlcat Dec 31 '19 at 03:12
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).

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Emperor XLII
  • 13,014
  • 11
  • 65
  • 75
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).

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • 2
    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. – Peter Mortensen Dec 07 '14 at 09:22
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Justin Yancey
  • 99
  • 1
  • 1
  • +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. – Christian Mikkelsen Mar 01 '12 at 10:15
  • 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! – Neville Jul 14 '13 at 23:06
  • What are WASP, PSCX, and SCOM (in this context)? – Peter Mortensen Sep 01 '13 at 18:27
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
            );
        }
    }
}
granth
  • 8,919
  • 1
  • 43
  • 60
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jaykul
  • 15,370
  • 8
  • 61
  • 70
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
user10101
  • 1,704
  • 2
  • 20
  • 49