Differing output from Where and Where-Object

One of the lesser known features of PowerShell are some “magic” methods that get added to most (all?) collection objects that replace the slower Where-Object and ForEach-Object cmdlets with basically the same functionality. They’re considered magic because they aren’t well documented even years after they were introduced. (Thank goodness for bloggers) I’ve used ForEach quite a bit, but often forget about it’s Where counterpart and apparently had never actually done much with it until today when I ran into a weird issue where I couldn’t set the value of a property on a returned object.

The setup is a pretty classic needle-in-a-haystack problem where you have an array of objects and need to update a property on just one of them. Pretty classically you’d do something like this.

It works great but if you’ve got a really big array of complex objects it can start to take a long time to process. So today I had remembered the aforementioned magic methods and figured it would be a lot faster to use Where to do essentially the same thing. Except I got a really unexpected error.

Maybe it was returning a single element array? Running “$testElement -is [array]” said “False” but “$testElement[0].attr = ‘something'” worked just fine, so what was going on here? Time for some more “magic” in the form of the pstypenames property.

Of course while I was tinkering with all of that and doing some research on the Where and ForEach methods I ran across that article I linked further up and figured out the correct solution to the problem.

Finding an item in an array of PSCustomObjects

(This is mostly so I can find it again someday when I need it again.)

When working with REST interfaces with PowerShell it’s pretty common to get JSON responses that have information that is returned as arrays of PSCustomObjects. If you need to update a property of one of those objects you can’t just do something simple like:

In order to set the value of a property you’re going to have to find the index of that particular object in the array and then manipulate it directly. Thankfully this is easier than it sounds because we have access to the static methods of the .Net Array object, and FindIndex in particular. The previous example actually ends up being something like this:

Standardized Tests for Standardized Parameters

Something that you find when writing PowerShell modules to wrap API functions for external systems is that a lot of your functions tend to have a consistent subset of parameters that get used for things like credentials and specifying an endpoint. For example in the private TeamCity module that I maintain the parameter block for every function that interacts with a server has:

(Whether that is the best pattern I’m still not sure, but it’s beside the point of what I’m talking about here. If you have better ideas I’d love to hear about them!)

If you are writing good unit tests for your functions you need to test those parameters in every single one of those functions and ideally you want to test those parameters consistently to make sure that FunctionA doesn’t use them slightly differently than FunctionB. Additionally if I find a better way of testing those parameters I don’t want to have to update¬†dozens (or more!) of Describe blocks. There had to be a way of writing those tests once and then calling those tests¬†consistently when testing every one of those functions and it turns out to be pretty simple.

The trick is to consider that Pester is pretty consistent about scope inside the Describe and Context blocks so if we were to dot-source some external file in the correct context we should be able to inherit anything that’s in that file. Declaring variables with consistent test values and wrapping tests inside of a function definition means that we can do the dot-source in the scope of a Describe block and then reference those variables and call those sets of tests in every function’s tests.

For example, let’s start with a file called “StandardTests.ps1” that defines two variables and a function to test those two variables:

Then making uses of those variables and tests might look something like this:

The only thing left is to run the tests!
Successful Test output

Reporting Pester Code Coverage Metrics to TeamCity

As previously mentioned I’ve been doing a lot of work with PowerShell modules at work where I have recently gotten all the parts for a full continuous delivery pipeline working for those modules. A big section of that pipeline runs through TeamCity and while the existing ability to have Pester test results show up in the build results is really great, code coverage is slightly less obvious but in the end fairly simple.

The trick is to use the -PassThru parameter with Invoke-Pester and then use TeamCity’s build reporting interaction to get the values into the system. The end result will look a lot like this:

Pester code coverage right in your TeamCity build results!
Pester code coverage right in your TeamCity build results!

Simple test coverage check for script modules

I’ve been spending a lot of time at work writing PowerShell modules and as part of that effort we’ve been trying to make sure we’re doing at least some unit testing on those module functions (Using Pester of course!). Unfortunately we’ve had a few instances where a new function gets added to a module without any unit tests being added. We’ve structured our modules so that every function has it’s own source file and accompanying tests file and all of them are located in a \Functions\ folder in the project. Ideally the CodeCoverage parameter for Invoke-Pester would catch this sort of problem but it only runs tests for files with a certain file name structure and so if it runs across Some-Function.ps1 without an accompanying Some-Function.Tests.ps1 it doesn’t care. Today I finally got a little tired of finding broken functions and decided to do something about it, the result is Coverage.Tests.ps1:

I’ve got to think that it shouldn’t be hard to add a similar test for my other pet peeve: Missing help comment blocks!