An introduction to infrastructure testing with PowerShell Pester

In a Windows world, the scripting language of choice is PowerShell, and thus the testing framework is probably going to be Pester. In this article, we'll extend a unit testing framework (Pester) into an infrastructure testing framework and cover a couple scenarios where it might come in handy.

When a software developer is asked about testing, they'll most likely talk about unit, integration, functional, or acceptance testing. These are the kinds of tests that have been around for decades and are considered formal testing strategies. Then, one day, system administrators decided they wanted in on the coding action, and infrastructure development was born. I'm going to define an "infrastructure developer" as anyone that writes code to provision and manage any kind of infrastructure.

Infrastructure code, by its nature, changes stuff in an environment. It provisions VMs, installs software, copies files, and so on. It's advisable to write unit tests to check the code itself, integration tests to ensure the code changed the stuff you intended, and acceptance tests to test the result. However, there's a gray area in there that's like a combination of integration and acceptance testing; I'm calling this infrastructure testing.

Infrastructure testing is primarily testing the result of infrastructure code or just ensuring the infrastructure works as expected; no code involved at all. Think of infrastructure testing as simply writing code to ensure servers are online, registry keys are created in the right spot, files are where they're supposed to be, user accounts are created correctly, etc.

To demonstrate infrastructure testing, let's cover a common task: provisioning new users in Active Directory. A PowerShell script this might look something like this:

You can see that I'm just assigning a few variables to some user properties and then running New-AdUser to create the user account. Let's say I run this and I get no output. No errors? Great! It worked! Maybe. How do you know it worked? Just because you didn't see a sea of red text doesn’t necessarily mean it created the account. For all we know, you might have had $ErrorActionPreference inadvertently set to SilentlyContinue. It's important that we test the result of this code. Let's build an "infrastructure" test with Pester.

Since this script creates an AD user, I'll name the describe block accordingly.

Now comes the fun part: actually creating the It blocks (the tests themselves). When creating an infrastructure test, it's important to ask yourself: "What does this code actually do?" We know it creates an AD user. Sure. But we must get more granular than that. What is this code changing in my environment? It's creating an AD object, and objects have properties. We need to ensure not only that the user account was created but also that the object that was set up has all of the properties we expect.

Spotting the properties in this script is easy. Since it's a single command, we'll just look at the parameters like FirstName, LastName, etc. However, it's not so easy in larger scripts. The key is to separate out "functional" code and logic from the actual data that's changing. Indicators such as defined parameters, variables, etc. are typically a safe bet to test.

In this example, I'm going to ensure an AD user was created, and the following attributes were defined correctly:

  • FirstName
  • LastName
  • Username
  • Department
  • Enabled

To be as verbose as possible, I'm going to create separate tests for each attribute. This isn't necessarily required, but it allows you to easily see what's being tested. But first, we'll need to ensure that the user object was created. After all, if a user can't be found, we're not going to be able to test the properties of that object.

We'll first define each of the expected values of each attribute so they can be referenced later.

I like to define all expected values early in a hash table so it makes them explicit and easily changeable.

Next, I'll grab the user account:

I will then save this in a Tests file and run it.

Save the script in a Tests file and run it

Save the script in a Tests file and run it

Save the script in a Tests file and run it

Oops! Notice that it correctly created everything except for the department. Looking back up at the original script, it looks like I fat-fingered the department. I'm glad I created the test! If not, this would have gone unnoticed.

If you're not writing Pester tests to test infrastructure code, start now. You can see that it's easy to do and might just save you from a lot of headaches in the future. For more information on infrastructure testing and Pester, in general, check out The Pester Book by myself and Don Jones.


Join the 4sysops PowerShell group!

Your question was not answered? Ask in the forum!


Leave a reply

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2020


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account