Sunday, August 01, 2010

Using Newer Version(s) of .NET with PowerShell

I’ve been playing around a bit with the latest version of the .NET Framework. There are some pretty cool new classes and namespaces but one that caught my eye was System.Numerics. This namespace has two neat classes: System.Numerics.BigInteger and Sytem.Numerics.Complex – these represent big integers and complex numbers respectively. To demonstrate the BigIngteger class, I’ve written two small scripts: New-BigInteger.ps1 and Get-BigIntegerProperties.ps1 (with more to come!). You can get these and several hundred more PowerShell scripts from my Powershell Scripts blog. When I first started to develop these scripts, starting first to translate an MSDN sample from C# into  PowerShell, I came across some curious errors. In the end learned how to call updated versions of the .NET Framework.

By default, PowerShell uses .NET version 2.0. But if you want to use classes implemented in later versions of the Framework (in namespaces that are not loaded by default of course), you first need to load the relevant dll. You can do this as follows:

Add-Type -Path "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Numerics.dll"

But there’s only one problem (by default!) – when you do this you get the following run time error:

Add-Type : Could not load file or assembly 'file:///C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Numerics.dll' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.
At line:1 char:9
+ Add-Type <<<<  -Path "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Numerics.dll"
    + CategoryInfo          : NotSpecified: (:) [Add-Type], BadImageFormatException
    + FullyQualifiedErrorId : System.BadImageFormatException,Microsoft.PowerShell.Commands.AddTypeCommand

The solution is pretty simple – just tell PowerShell to use a later version of the CLR. To do this, you need to create a config file, named PowerShell.Exe.Config, located in the same folder as PowerShell.Exe (and another one for PowerShellISE.Exe, or PowerShellISE.Exe.Config). These config files contain a small bit of XML to tell the system which version of the CLR to use. To access the .NET 4.0 versions, use the following:

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

With this XML created, just restart PowerShell and you can add the System.Numerics.Dll and use the classes in that namespace!

10 comments:

Unknown said...

the only issue is PSRemoting still uses .net 2.0 so if you try to load something remote that is 4.0 it still fails.

Karl said...

I can't get your fix to work. When I try to run the "Add-Type" command, I get the same message after adding the config file (and restarting PowerShell). Can you suggest anything I could try? I build and addin with Visual Studion 2010, and it is using the 4.0 framework.

Thomas Lee said...

@Paul
Yes - that is probably the case. In order to fix that, you need to create a config file for the remoting exe target (wsmprovhost.exe).

I've not tried it, but I would imaging creating a wsmprovhost.exe.config with the same contents would solve the problem.

Thomas Lee said...

@Karl

I'd double check the .config file is typed correctly and is in the same folder as the .exe. When .NET loads an .exe file, it checks the .config file for things to do - like bind to a different version of .NET than was originally planned.

Updating the .config file should work - the only things I can think of are typos...

Karl said...

A little further, but still not quite successful. I managed to get the first DLL to register and the alias defined, but InstallUtil still gives me the "built with a newer version" error.


For the record, I discovered another powershell.exe in C:\Windows\SysWOW64\WindowsPowerShell\v1.0\ which is run from the start menu (and gives the command window with the blue background) I had to add the config file there as well.

Ernie said...

Thanks Thomas, your the man!

I was getting to the bottom of my problem, and yet again you helped me out with this post :)

Ernie

Ernie said...

You saved my life again Mr Lee :)

Thanks for posting

Ernie

Unknown said...

Its Superb blog , if Rundll error problem go through this link and get free from error.
How To Remove Rundll Error
Thank you
Aalia lyon

Unknown said...









Hi Thomas, where to save this Code or past this XML Code so that I can resolve this Error on my PS.

Thomas Lee said...

Raman, as the article says:

"To do this, you need to create a config file, named PowerShell.Exe.Config, located in the same folder as PowerShell.Exe (and another one for PowerShellISE.Exe, or PowerShellISE.Exe.Config)"