In my quest to figure out why handles.ps1 was running very slowly when looping over the 3.4 million handles on my system, I started to realize that the loop structure itself was a lot slower than a language like C#. I know that PowerShell is compiled to an executable lambda statement when it meets particular criteria so I went to figure out what a loop looks like when it’s compiled. The aptly named Compiler class takes care of this. The Compiler class is invoked on ScriptBlocks to generate in-memory functions that are a representation of that block. The Compiler class is an implementation of a ICustomAstVisitor2 that is developed to “Visit” each type of expression in a block. Example of this are ForEachStatementAst and ReturnStatementAst.

While perusing the source code for the Compiler class you’ll come across a lot of Visit* methods. Each of these methods takes a particular part of the PowerShell AST and turns it into a LINQ Expression that can then be used to generate a executable lambda. Let’s look at what makes up a couple of the looping statements.

While Loops

While loop are the basis for a lot of other loops when you break down the Compiler class. The while loop is actually implemented by using several different labels and gotos to achieve loop functionality. At the top of the GenerateWhileLoop method, you’ll see a comment that defines the pseudo-code for a PowerShell while loop.

There are 3 different distinct labels. The LoopTop, BreakTarget and ContinueTarget. Gotos will jump to the various labels based on whether you use the continue or break keyword or move to the next iteration of the loop.

Given the loop: while($true) { }

The resulting output will be:

ForEach Loops

ForEach loops are just a modification of the while loop. The comment in the Compiler class states the pseudo-code for a loop looks like this.

You can see that the ForEach is just turned into a while statement that uses the IEnumerable class to call MoveNext and Current to move through the collection.

Given the loop: foreach($x in $i) { }

The resulting output will be:

For Loops

For loops are again a modification of the while loop but with the added control and condition of the iterator.

Given the loop: for($i = 0; $i -lt 10; $i++) { }

The resulting output will be:

So there is a lot more going on when PowerShell is looping than when languages like C# are looping. Might be why my functions are a little slow. 😉