For those who are in the tank we report: PowerShell 3 will be officially released along with Windows 8. CTP appeared along with the release of Windows 8 Developer Preview (at the conference // Build / from Microsoft in September 2011). The second CTP release appeared right under Christmas.
For several months I had the opportunity to play around with PowerShell 3 and now I want to tell you about my impressions.
Introduction
With this release, a lot of things have been released, but for me (
and me - approx. Transl. ) The main change is that PowerShell is now based on Dynamic Language Runtime, i.e. on an environment that allows you to embed dynamic languages ​​(
eg, IronRuby, IronPython - approx. transl. ) in Common Language Runtime (CLR), which in turn is the core of the .NET Framework. DLR makes it easy to develop dynamic languages ​​that run on the .NET Framework. Of course, PowerShell was originally a dynamic language in the .NET framework, but it appeared earlier, so historically it was not associated with the DLR. And just now PowerShell has been permanently transferred to the DLR.
Although PowerShell 3 is implemented using DLR, it is not a dynamic language in all respects compared to IronPython or IronRuby. Let me give you a couple of diagrams from the DLR documentation.
The DLR Overview

On the diagram you can see three main sections (in the DLR implementation on CodePlex): hosting, runtime and language. But be that as it may, not all of them are ported to the .NET Framework 4.0 CLR.
Ported DLR
* The diagram in pink highlights what has been moved to CLR 4.0 - approx. trans.PowerShell 3 takes advantage of all (or almost all) of what is ported to the CLR, but because of the reluctance, the development team did not take the rest of the DLR into porting the operating system. Thus, PowerShell 3 uses DLR Language Implementation functionality, together with Shared AST and Expression trees, as well as DynamicObject and Call Site Caching runtime, but does not use anything from Common Hosting - ScriptRuntime, ScriptScope, ScriptSource or CompiledCode.
This means that you cannot use the IronRuby and IronPython script hosting APIs for PowerShell. But you can use the same API that is used for hosting PowerShell 2, only instead of PSObject you will need to use Dynamic when processing output in C #. And this is actually an important thing.
I would not like to consider all the changes that you will encounter in PowerShell 3 and which were a direct consequence of the transition to DLR. However, there are several serious things to look out for. First, you may notice a difference in performance and performance. The fact that you knew about the performance ratio of Scripts, Functions and Commandlets, as well as the download time of scripts and binaries, has sunk into oblivion with the release of PowerShell 3, since Now scripts and functions are no longer interpreted before each call, but compiled, executed and even cached (from time to time). As a result, the first launch and the first import of the script is somewhat longer than expected, but all subsequent calls to scripts and functions from them are performed much faster. And this applies to all scripts in files and predefined functions in modules. Sequential launching of the same function several times now happens much faster than pasting one and the same code several times into the console.
Another major change is the abandonment of PSObject.
In PowerShell 3, PSObject is actually a dynamic object, and this means that the output of cmdlets and scripts called from C # can be used with the keyword “dynamic” instead of using pseudo-reflection methods that were used with PSObject. By the way, this is only the tip of the iceberg.
In PowerShell 2, everything in the Extended Type System (ETS) was based on PSObject. New members were always added to PSObject, which used BaseObject to turn around - no matter if they came from the “types.ps1xml” file or from the “Add-Member” call on the object. If the Add-Member method was invoked on an object that was not wrapped in PSObject, then it was necessary to specify the "-Passthru" parameter and process the output in order to have the object wrapped in PSObject to which the new member can be added. In addition, if the object was cast to some type, the added ETS members were lost in most cases. Below is an example script:
$psObject = Get-ChildItem $psObject.Count $Count1 = ($psObject | where { $_.PSIsContainer }).Count [IO.FileSystemInfo[]]$ioObject = Get-ChildItem $ioObject.Count $Count2 = ($ioObject | where { $_.PSIsContainer }).Count $Count3 = ($ioObject | where { $_ -is [IO.DirectoryInfo] }).Count
In PowerShell 2, $ Count1 and $ Count3 will contain the number of folders in the current directory, and $ Count2 will always have the value 0, since the PSIsContainer property is actually an ETS property that is lost when casting to FileSystemInfo, which is why this variable is always evaluated as zero.
In PowerShell 3, the same result will be different. PowerShell now works with everything as a dynamic object, and the Add-Member no longer needs a PSObject to track these ETS members. So now the script presented above will return $ Count1, $ Count2 and $ Count3 the same, as expected. Obviously, the "-Passthru" option in the Add-Member is only needed to tunnel things, and not for simple assignment. But be that as it may, there may still be cases where entities still need to be wrapped in a PSObject.
I think you will agree that transferring PowerShell to DLR is a big step forward! But be prepared for major changes that can break the already implemented functionality. For example, try adding the following three lines to the script above and run them in PowerShell 2 and PowerShell 3 CTP2:
$Count1 -eq $Count2 $e = $ioObject[0] | Add-Member NoteProperty Note -Passthru $f = $ioObject[0] | Add-Member NoteProperty Note -Passthru
In PowerShell 2 you get False, and the next two lines will work fine. In PowerShell 3, the first line will return True, and due to the fact that the Add-Member modifies the underlying object even unwrapped in the PSObject, the third line will generate the error "Add-Member: Can't add a member" already exists. "
In any case, I am sure that in the future I will write something else about the DLR and what changes have occurred in PowerShell with the transition to it. But while food for the mind, I think, will be enough.