2017-04-07

Out-Default: Secrets Revealed

Intro

You may or may not know that Out-Default plays a very important but silent role in your everyday use of of PowerShell. If you don't know the role it plays, you may want to check out this post by Jeffry Snover. I had always had my suspicions about how the Console Host in PowerShell works, but during a recent discussion on /r/PowerShell I was linked to Snover's post and had many of my suspicions confirmed directly from the source.

But, after reading, re-reading, and re-re-reading the post I was left wondering about the specifics of when Out-Default is actually called. It wasn't clear to me if it was only attached to a line of input from the console, or attached to the end of every line of every piece of processed code, or if this done in a non-interactive session or not. I decided it would be fun to investigate this using PowerShell itself and even more fun to share my process and findings.

Test Methodology

One of my favorite things about PowerShell is how easy it is to investigate and manipulate everything in PowerShell except for the language primitives. Pretty much any function, cmdlet, or alias can be "hijacked". What I mean by "hijacked" is that you can replace even core functions like Out-Default with your own code. While this obviously isn't always a good idea, has a few security implications, and some major performance impact implications, it also has some amazing investigative use-cases.

The setup for this investigation is simple. I'm going to create a proxy function to wrap around Out-Default. Then I'm going to increment a Global variable each time the proxy function is called and update the contents of a file. This is akin to early web site visitor or hit counters. The reason for using the file instead of just looking at the variable itself is that we are trying to reduce the observer effect. If we were just to look at the variable contents every time and that happened to trigger a call to Out-Default, it would update the variable and pollute our results.The variable needs to be Global scoped because we need to test Out-Default being called in all scopes.

We will then run a series of lines of code. The same tests will be done from the PowerShell console, PowerShell ISE, and from a non-interactive session. For both the PowerShell Console and ISE we will test running individual lines, grouped lines, and multiple commands run on the same line separated by semi colons. After each test we will investigate the output file and the number contained therein should reveal the number of times Out-Default was run.