This page looks best with JavaScript enabled

Pester 5 scope issues and calling PSScriptAnalyzer

 ·  β˜• 2 min read  ·  πŸ€– Javy de Koning

What is breaking in Pester 5

After the GA release of Pester 5 some of my tests started failing. You can find an overview of breaking changes on this GitHub issue as well as on the README here.

In Pester v4 the below example would work fine.

$Foo = 'Bar'

Describe "DescribeName $Foo" {
    Context "ContextName $Foo" {
        It "ItName $Foo" {
            $Foo | Should -Be 'Bar'

However, in version 5 $Foo no longer ‘leaks’ to the It block. This results in the following error:

Describing DescribeName Bar
 Context ContextName Bar
   [-] ItName Bar 10ms (7ms|2ms)
    Expected 'Bar', but got $null.

The reason for this is described explicitly in the readme:

The scoping is very similar to Pester v4, but without the quirks. BeforeAll, Describe, and AfterAll now run all in the same scope, and are isolated from their parent scope, to avoid leaking variables outside of their scopes, for example into the script scope. This prevents test cross-pollution and makes your tests more repeatable.

PSScriptAnalyzer tests in v4

In v4, you could just loop over the PSScriptAnalyzer rules as follows:

Describe 'PSScriptAnalyzer analysis' {
    Foreach ( $Rule in (Get-ScriptAnalyzerRule)) ) {
        It "Should not violate rule: $($Rule.RuleName)" {
            Invoke-ScriptAnalyzer -Path "..\module.psm1"`
            -IncludeRule $Rule.RuleName |
            Should -BeNullOrEmpty

How to do it in v5

In Pester v5, we need to handle this differently. I would suggest using TestCases like so:

β”œβ”€β”€ tests
|   └── PSSCriptAnalyzer.Tests.ps1
└── module-to-test.psm1

Your PSSCriptAnalyzer.Tests.ps1 would look like this:

$Modules = Get-ChildItem (Split-Path $PSScriptRoot -Parent)`
-Filter '*.psm1'

$Modules | ForEach-Object {
    Import-Module $_.FullName -Force

if ($Modules.count -gt 0) {
    Describe 'PSScriptAnalyzer analysis' {
        It "<Path> Should not violate: <IncludeRule>"`
        -TestCases @(
            Foreach ($m in $Modules) {
                Foreach ($r in (Get-ScriptAnalyzerRule)) {
                        IncludeRule = $r.RuleName
                        Path        = $m.FullName
        ) {
            param($IncludeRule, $Path)
            Invoke-ScriptAnalyzer -Path $Path`
            -IncludeRule $IncludeRule |
            Should -BeNullOrEmpty

This brings along some minor issues. Today for example, you cannot access a nested hashtable in the it statement, hence you would need to always flatten the object.

Find Pester on GitHub:

pester/Pester - GitHub

Want to learn more about Pester v5?

Check out this excellent presentation by Jakub JareΕ‘ (@nohwnd)

Javy de Koning
Javy de Koning
Geek πŸ€“, Love sports πŸƒβ€β™‚οΈπŸ‹οΈβ€β™‚οΈ, Food πŸ›, Tech πŸ’», @Amsterdam ❌❌❌.