Sergey Nivens - Fotolia

Evaluate Weigh the pros and cons of technologies, products and projects you are considering.

Pester PowerShell unit testing ensures quality code

PowerShell jockeys can turn to the Pester unit testing framework to ensure the code they write is up to snuff.

PowerShell is not just for quick, ad hoc tasks anymore -- it underpins the configuration of entire IT estates -- and one bad line can disrupt the deployment of systems and applications.

PowerShell's evolution from a fledgling scripting language into a full-featured automation tool makes it a must for any administrator's toolbox. Large organizations increasingly rely on PowerShell to provision virtual environments, manage critical code deployments and orchestrate many other business-critical tasks.

This increased reliance on PowerShell requires IT to ensure scripts' reliability. This is where Pester, a PowerShell unit testing framework, can help. Pester tests how PowerShell scripts execute before they reach live systems. It's the only PowerShell testing framework available. It's important enough that Microsoft packages Pester in Windows Server 2016 and Windows 10.

Build a script for PowerShell unit testing

Pester enables users to write simple PowerShell unit tests for scripts of varied complexity. For example, an administrator wrote a script that provisions virtual machines for the fictional Acme company, and names the script New-AcmeVm.ps1. The first part of the script creates a Microsoft Hyper-V VM with various attributes. A key piece of the script determines what name to assign to the VM, such as SRV1, SRV2, SRV3 and so on, or a different naming convention.

The script assigns the server name with the next available number when it creates a new VM. This part is crucial for the rest of the script to finish successfully. A sample of that script looks like:

function Get-VmName {


## Find existing VMs

$existingVms = Get-Vm

## Get the new VM's number

$number = $existingVms.Name | foreach {

           $_ -replace '^SRV'

} | Sort-Object –Descending | Select –First 1


     ## Return the name

"SRV$([int]$number + 1)"


Time to pester PowerShell with tests

Microsoft packages Pester in Windows 10 and PowerShell 5. Administrators can also download Pester with the Find-Module –Name Pester | Install-Module command.

Pester unit tests are PowerShell scripts with an optional -- yet recommended -- naming convention. In Figure 1, a command in Pester called New-Fixture creates the testing template:
New-Fixture –Name New-AcmeVM.

This builds the script and a tests file.

PowerShell Pester tests
Figure 1. At the start of the testing process, Pester creates a script and a tests template file.

Replace the New-AcmeVM.ps1 script with the script created earlier in this tutorial. The tests template file should look like this:

$here = Split-Path -Parent $MyInvocation.MyCommand.Path

$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'

. "$here\$sut"

Describe "New-AcmeVm" {

  It "does something useful" {

    $true | Should Be $false



Replace the existing describe block with a fitting description:

describe 'New-AcmeVm' {

                it 'calculates the right VM name and passes it to the New-VM command' {




Powershell unit testing shows what you've got

Pester consumes tests in PowerShell script blocks, which are statements or expressions compiled into a unit to take arguments and return values.

The parent block is always the Describe block. This is a parent container for individual PowerShell unit tests. Inside the describe block, add some Pester tests with the It blocks. It blocks contain the PowerShell code that validates the code the administrator wants to test. It blocks are logical groups of code that separate different functionality. In this example, there is just a single It block because the only test is to verify that the VM is named correctly.

Next, use a Pester mock, which is a way to create fake dependencies and check behavior, to test the script with the following:

describe 'New-AcmeVm' {

                mock 'Get-Vm' {

                                [pscustomobject]@{Name = 'SRV1'}


                it 'calculates the right VM name and passes it to the New-VM command' {

                                Get-VmName | should be 'SRV2'



The mock "overwrites" the original Get-VM command to return a single object that represents a test sample of VM names. The mock also has an assertion to test the result of Get-VmName. Run the test with the following command to see the result:

Invoke-Pester -path C:\New-AcmeVM.Tests.ps1

PowerShell Pester test.
Figure 2. The Pester test returns a passing result.

Figure 2 shows the test is a success -- when the script with the Get-VmName function runs, it will always return the correct name.

Next Steps

Refresh your PowerShell scripting basics

Build functions that support the PowerShell pipeline

Use support parameters to simulate PowerShell output

Try PSScriptAnalyzer to check PowerShell code best practices

Dig Deeper on Windows administration tools