---
title: "Master PowerShell Testing with Pester"
description: "Write effective PowerShell tests using the Pester testing framework, as taught by the author of The Pester Book."
canonical: "https://adamtheautomator.com/powershell-test/"
---

# Master PowerShell Testing with Pester

> Write effective PowerShell tests using the Pester testing framework, as taught by the author of The Pester Book.

Source: https://adamtheautomator.com/powershell-test/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![Master PowerShell Testing with Pester](https://adamtheautomator.com/wp-content/uploads/2019/07/pesterbook.png)

# Master PowerShell Testing with Pester

[![](https://secure.gravatar.com/avatar/d0b9d42e21e5622713f8b693aa5c0f9244d5f7dd200ed29b8398f52dee5de337?s=192&d=mm&r=g)Adam Bertram](https://adamtheautomator.com/author/adam-bertram/)8 July 20198 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[Pester](/tag/pester/)[PowerShell](/tag/powershell/)

Table of Contents

*   [Installing Pester](#installing-pester)
*   [Creating a PowerShell Pester Test](#creating-a-powershell-pester-test)
*   [Running the Test with PowerShell](#running-the-test-with-powershell)
*   [Writing A Passing Pester Test](#writing-a-passing-pester-test)
*   [How this PowerShell Test Worked](#how-this-powershell-test-worked)
*   [Understanding Pester Blocks](#understanding-pester-blocks)
*   [Describe Blocks](#describe-blocks)
*   [Context Blocks](#context-blocks)
*   [It Blocks](#it-blocks)
*   [Before and After Blocks](#before-and-after-blocks)
*   [Summary](#summary)

> _This is a two-chapter example from my book [The Pester Book](http://pesterbook.com). If want to learn how to test PowerShell code, the unit testing framework Pester is the de facto way to do it. This is the intro chapter. [The Pester Book](http://pesterbook.com) has over 200 pages of real-life, in depth examples covering every aspect of Pester and testing methodologies._

So you’re ready to take the next step in PowerShell development by writing tests? That’s great! To give you a peek at what you’re in for in this book, let’s go through what it takes to write Powershell tests with the [PowerShell module](https://adamtheautomator.com/powershell-modules/), Pester.

Not a reader? Watch this related video tutorial!

**_Not seeing the video? Make sure your ad blocker is disabled._**

Whether you’re a professional software developer or weekend PowerShell scripter, Pester is the tool you need to test PowerShell code.

## Installing Pester

Pester is preinstalled on Windows 10 and later, and on Windows Server 2016 or later. Pester currently works back to PowerShell v2. If you have the [PowerShell Package Manager](http://powershellgallery.com/) installed, you can use the `Install-Module` command to install Pester. If not, head to the project’s [GitHub page](https://github.com/pester/Pester) to download it as a ZIP file. When you extract the ZIP file, Pester will need to be in your _C:\\Program Files\\WindowsPowerShell\\Modules_ folder or any other folder in your’PSModulePath’ environment variable. You can look at this environment variable by running `$env:PSModulePath`.

Also, when you download Pester, your browser might mark the downloaded ZIP file as potentially unsafe. If so, use the `Unblock-File` command to unblock the ZIP file before extracting it. You can also right-click the file, and select _Properties_ from Windows Explorer to find an _Unblock_ button.

## Creating a PowerShell Pester Test

In your PowerShell console with Pester installed, you can quickly create a simple project. Pester provides a command called `New-Fixture` that scaffolds out a single PowerShell script and test file to work with. However, this command is now considered legacy and will be removed from future versions Pester. Don’t worry, though, creating a simple test is straightforward.

To build a Pester test, you need, at a minimum, two files: a PS1 script which contains code to test and a test script file. Create a folder called _Pester101_ somewhere, a PS1 script called _Pester101.ps1_ and an associated test script file called _Pester101.Tests.ps1_. Below is some code to get that done for you.

```powershell
PS> New-Item -Path 'C:\Pester101' -ItemType Directory
PS> New-Item -Path 'C:\Pester101\Install-Pester.ps1' -ItemType File
PS> New-Item -Path 'C:\Pester101\Install-Pester.Tests.ps1' -ItemType File
```

Inside of _Install-Pester.ps1_, create a single function (you’ll learn Pester _loves_ functions), called `Install-Pester` and leave it blank. The function name can be anything.

```powershell
function Install-Pester {
    param()

}
```

Once you have the _Install-Pester.ps1_ script created, now add the following code to the _Install-Pester.Tests.ps1_ file at the top. The first three lines code aren’t related to Pester, per se; it’s merely a way to [dot sourcing](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts?view=powershell-6#script-scope-and-dot-sourcing) the function inside of _Install-Pester.ps1_ to make available inside of this test script. The _describe_ block below that is where the magic happens.

```powershell
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

describe 'Install-Pester' {
    it 'does something useful' {
        $true | Should -Be $false
    }
}
```

Congratulations! You’ve officially created your first Pester test!

## Running the Test with PowerShell

Now that you have a basic test scaffold built out let’s run the test as-is and see what happens. At this point, you haven’t put any code into the `Install-Pester` function in the _Install-Pester.ps1_ file. The function does nothing.

If you’re not already, change to the _C:\\Pester101_ folder then run `Invoke-Pester`.

```powershell
PS> cd C:\Pester101
PS> Invoke-Pester
```

When `Invoke-Pester` runs, it will automatically look for any files ending with _Tests.ps1_ in the same folder you’re in or any subfolders. If it finds one, it runs it.

![Failing Pester Test](/wp-content/uploads/2019/07/image-22.png)

Failing Pester Test

Notice the `[-]` and red text. This indicator means that the test has failed. Below that indicator, it will tell you why. In this instance, it has failed because the boolean value `$false` was supposed to be `$true` which, as you probably know, is not valid. Unit tests in Pester are returning true or false.

## Writing A Passing Pester Test

So you’ve failed but don’t sweat, I’ll help you pass this test. Open up the _C:\\Pester101\\Install-Pester.ps1_ file in your favorite editor and insert a single line `Write-Output "Working!"` as shown below.

```powershell
function Install-Pester {
    param()
    Write-Output "Working!"
}
```

Save the file and now open the _C:\\Pester101\\Install-Pester.Tests.ps1_ file. Replace the entire _describe_ section with the below code.

```powershell
describe 'Install-Pester' {
    it 'outputs a string' {
        Install-Pester | Should -Be 'Working!'
    }
}
```

Now, run `Invoke-Pester` again while in the _C:\\Pester101_ folder and see what happens.

![PowerShell Pester Test Pass](/wp-content/uploads/2019/07/image-21.png)

PowerShell Pester Test Pass

Notice now that your test has passed indicated by the `[+]` and green text.

## How this PowerShell Test Worked

You’ve now successfully gone through all there is to create and run tests in Pester, but how did that work anyway?

1.  You created two files; _Install-Pester.ps1_ and _Install-Pester.Tests.ps1_ in the _C:\\Pester101_ directory.
2.  The _Install-Pester.ps1_ script represented the code to test. The _Install-Pester.Tests.ps1_ script held the tests to run against the code in _Install-Pester.ps1._
3.  When `Invoke-Pester` was run while inside of the _C:\\Pester101_ directory, it looked for all scripts ending in _.Tests.ps1_.
4.  Once `Invoke-Pester` found all of the scripts, it then ran each one (in this case, a single one).
5.  When the _Install-Pester.Tests.ps1_ test script was run, it dot sourced the _Install-Pester.ps1_ script so that Pester could run the `Install-Pester` function inside.
6.  Pester then executed that function inside of the test (doing nothing at all the first time) and then compared the boolean value `$true` with the boolean value `$false`. Since the test was expecting `$true` to be `$false`, it failed.
7.  On the second round, Pester dot sourced the `Install-Pester` function again, ran it and this time captured the output of `Working!`. It then compared that output to the expected output of `Working!`. Since they were both the same, the test passed.

## Understanding Pester Blocks

Pester’s domain-specific language (DSL) is heavily reliant on PowerShell scriptblocks. Scriptblocks allow Pester to segment code, control how it’s run and more. Scriptblocks are what will enable Pester to do most of the unit-testing magic it does! To understand Pester, you must first understand the various kinds of scriptblocks (blocks) that Pester uses to execute code.

In Pester’s DSL, you’ll see six types of blocks:

*   _Describe_
*   _Context_
*   _It_
*   _BeforeEach_/_BeforeAll_
*   _AfterEach_/_AfterAll_
*   Mocks

Each of these blocks provides Pester the ability to control the order in which code is executed when a test runs, control _scope_ to ensure one block’s activities don’t conflict with another or to allow a child scope to inherit the scope of its parent.

### Describe Blocks

The highest level in your test file is a _describe_ block. A _describe_ block is a logical grouping of tests. Each test file can have one or more _describe_ blocks. Nearly everything happens inside a _describe_ block. If a test file contains one or more describe blocks, _describe_ blocks are the containers for almost everything else.

Like all of the other blocks covered in this chapter, a _describe_ block is a PowerShell scriptblock that contains all of the code necessary to carry out a Pester test.

The _describe_ block, at its simplest, consists of a name and a scriptblock indicated by the opening and closing curly braces.

```powershell
describe 'Stop-MailDaemon' {
    ## Stuff goes in here
}
```

_Describe_ blocks also separate _scope_ that, when performing unit tests is critical to understand.

### Context Blocks

The next level down from a _describe_ block is the _context_ block. The _context_ block resides inside of a _describe_ block and provides a logical grouping of _it_ blocks which you’ll cover next. A _context_ block, like a _describe_ block has a name and a scriptblock definition that contains code inside of the _context_ block. They are optional so, unlike the _describe_ block, don’t have to be used to build tests.

```powershell
describe -Tag 'Linux' 'Stop-MailDaemon' {
    ## Describe-specific code in here
    context 'When the server is down' {
        ## Context-specific code in here
    }
}
```

_Context_ blocks not only allow you to organize tests better but they also allow you to define separate scopes which you’ll learn a lot more about in the Mocking Introduction chapter.

### It Blocks

_It_ blocks are the next step down from the optional _context_ block. _It_ blocks can be in a _describe_ block or a _context_ block. _It_ blocks _assert_ an expectation for your code. They contain the code that checks the actual state with the expected state. _It_ blocks are what most people are referring to when they talk about a Pester test.

_It_ blocks have a name and a scriptblock definition. The name of an _it_ block is up to you but its best practice to give it a descriptive name of what state it’s testing. Be sure to check out the Test Design Practices chapter for some guidance there.

For example, if you’re testing whether the code throws an exception, a good _it_ block name would be “throws an exception” or, if the test within checks to see if a script is executed, the name could be “the script runs.” Keep your names simple and to the point.

```powershell
describe -Tag 'Linux' 'Stop-MailDaemon' {
    it 'the script runs' {
        ## Code to compare the state to test with the real state
    }
    context 'When the server is down' {
        it 'throws an exception' {
            ## Code to compare the state to test with the real state
        }
    }
    }
}
```

An _it_ block (test) can have one of five possible results:

*   \[+\] _Passed_: The test ran, and the expectation was met.
*   \[-\] _Failed_: The test ran and the expectation was not met.
*   _\[?\] Inconclusive_: The test ran but it did not pass nor did it fail.
*   \[_!\] Skipped_: The test was not run because it was put in a skipped state.
*   _\[?\] Pending_: The test was not run because it was empty or is pending.

We cover the skipped, pending and inconclusive states in depth in the Controlling Test Results chapter.

### Before and After Blocks

By default, Pester runs code from top to bottom. However, there may be times when you need code run before any _it_ blocks, right after or in between. In this case, you would use one or more _BeforeAll_, _BeforeEach_, _AfterAll_, or _AfterEach_ blocks. These blocks run arbitrary code that executes at certain times during the test run.

These blocks can contain whatever arbitrary code you need. They may set up some logging, create a database connection, or whatever else you need. They can appear in a _describe_ or a _context_ block. These blocks are dot-sourced into the _context_, or _describe_ in which they appear, meaning they can also do things like define variables, which would then be “visible” to any _it_ blocks in the same _describe_ or _context_. It doesn’t matter where within the _describe_ or _context_, these blocks appear, nor does it matter in which order they appear. However, for readability, it’s customary to put _BeforeAll_/_BeforeEach_ blocks at the top of the _describe_ or _context_ block, and to put _AfterAll_/_AfterEach_ blocks at the bottom.

```powershell
describe -Tag 'Linux' 'Stop-MailDaemon' {
    BeforeAll {
        ## Code in here
    }
    BeforeEach {
        ## Code in here
    }

    it 'the script runs' {
        ## Code to compare the state to test with the real state
    }

    context 'When the server is down' {
        it 'throws an exception' {
            ## Code to compare the state to test with the real state
        }
    }
    }
    AfterEach {
        ## Code in here
    }
    AfterAll {
        ## Code in here
    }
}
```

The names are self-explanatory.

*   _BeforeAll_ runs _before any_ _it_ block runs.
*   _AfterAll_ runs _after all_ _it_ blocks have run.
*   _BeforeEach_ runs before each _it_ block runs-meaning, if you have five _it_ blocks, _BeforeEach_ runs five times.
*   _AfterEach_ runs _after each_ _it_ block runs.

If you define _BeforeEach_/_AfterEach_ in a _describe_ block and also within a child _context_ block, the ones in the _describe_ block run first, followed by the ones in the _context_ block. For example:

```powershell
describe -Tag 'Linux' 'Stop-MailDaemon' {
    BeforeEach {
        ## Runs first
    }

    it 'the script runs' {
        ## Code to compare the state to test with the real state
    }

    context 'When the server is down' {
            BeforeEach {
                ## Runs second
            }
        it 'throws an exception' {
            ## Runs third
        }
    }
    }
}
```

Have you ever used _try_/_catch_/_finally_ blocks in PowerShell? This is what Pester uses under the covers. Pester places the _Before_\* code before all others. Then, once the _it_ block, or _describe_ block has completed execution, Pester inserts code contained in the _AfterEach_ or _AfterAll_ blocks into a _finally_ block for execution.

## Summary

This two-chapter sample of [The Pester Book](http://pesterbook.com) is a great starting point for anyone wanting to learn about writing PowerShell tests. Building tests for your PowerShell scripts will definitely up your PowerShell game to a new level!

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-test%2F&text=Master%20PowerShell%20Testing%20with%20Pester)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-test%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-test%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

![](https://adamtheautomator.com/wp-content/uploads/2025/01/featured-image-1.png)

### [PowerShell Pester 101: A Practical Guide for Beginners](/powershell-pester-testing-guide/)

Learn how to validate your PowerShell scripts with Pester testing. This hands-on guide shows you how to write tests that ensure your code works as intended.

![](https://adamtheautomator.com/wp-content/uploads/2024/05/2024-05-10_08-07-57.jpg)

### [PowerShell Testing Mastery with Data-Driven Pester](/pester-infrastructure-data-driven-tests/)

I’ve been using Pester for a long time off and on. I’ve always been obsessed with ensuring reliability in my PowerShell code. After writing the Pester Book and

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
