Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Pester migration skill for upgrading PowerShell Pester test suites across major versions — v3→v4, v4→v5, and v5→v6. Covers the Discovery/Run two-phase model, moving setup into BeforeAll, $PSScriptRoot vs $MyInvocation, mock changes (Assert-MockCalled → Should -Invoke, removed fall-through), Invoke-Pester parameters → PesterConfiguration, data-driven -ForEach/-TestCases, and the v6 breaking changes. Use when the user asks to upgrade, migrate, or modernize Pester tests, fix *.Tests.ps1 files that
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 180% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 75% | 0% |
Pester is the test framework for PowerShell. Test files end in *.Tests.ps1 and use Describe / Context / It blocks with Should assertions. This skill upgrades an existing suite from one major Pester version to the next and gets it green again.
> Mental model: each major jump has a different character. v3→v4 is mostly a syntax > rename. v4→v5 is a fundamental runtime change (the Discovery/Run split) and is the hard > one. v5→v6 is largely backwards-compatible — a handful of previously-deprecated things now > throw. Migrate one major at a time; never skip a version.
Detailed, symptom-driven guides live in references/ — load the one(s) for the jump you are doing.
| Reference | When to load | |---|---| | v3-to-v4.md | Should Be → Should -Be, Contain → FileContentMatch, Assert-VerifiableMocks → Assert-VerifiableMock, array-assertion edge cases. | | v4-to-v5.md | The big one. Discovery/Run phases, BeforeAll setup, $PSScriptRoot, BeforeDiscovery, -ForEach, mock scoping, Should -Throw wildcards, Invoke-Pester → New-PesterConfiguration. | | v5-to-v6.md | PowerShell 5.1/7.4+ only, per-file discovery+run, empty -ForEach throws, duplicate setup blocks throw, name <...> templates evaluate, Assert-MockCalled removed, mocks no longer fall through, code-coverage tracer, legacy Invoke-Pester params removed. |
Canonical source: the official migration guides at https://pester.dev/docs/migrations/ — this skill mirrors them. When in doubt, prefer the website.
Find the installed version(s) and the version the tests were written for. These can differ.
powershell# Installed Pester version(s) on this machine Get-Module Pester -ListAvailable | Select-Object Name, Version, Path # Version currently imported in the session (Get-Module Pester).Version
Tell the source version from the test code with these heuristics:
| You see in *.Tests.ps1 / build scripts | Suite was written for | |---|---| | Should Be / Should Contain (no dash) | v3 or earlier → start at v3-to-v4 | | $MyInvocation.MyCommand.Path + dot-source at the top of the file; arbitrary code directly under Describe | v4 → v4-to-v5 | | Assert-MockCalled, Assert-VerifiableMock, Set-ItResult -Pending | v4 / early-v5 (these are removed in v6) | | Invoke-Pester -Script … -OutputFile … -CodeCoverage … (legacy params) | v4 invocation → map to config | | BeforeAll { . $PSScriptRoot/… }, New-PesterConfiguration, Should -Invoke | already v5-style → v5-to-v6 |
Install the target version when ready:
powershell# Latest stable v5 — pin the major to avoid installing Pester 6 Install-Module Pester -MaximumVersion 5.99.99 -Force # Pester 6 Install-Module Pester -Force
> On Windows PowerShell 5.1 the OS ships a Microsoft-signed built-in Pester 3 that PowerShellGet > won't overwrite with the differently-signed newer Pester — add -SkipPublisherCheck there to > install side-by-side. Not needed on PowerShell 7+. See > https://pester.dev/docs/introduction/installation.
Run this loop for each major jump. Do not jump two majors at once — go v4→v5, then v5→v6.
known-good (or known) starting point so you can tell migration regressions apart from pre-existing failures. powershell # Bare Invoke-Pester works on every major; exact parameters differ # (v3/v4: -Script/-OutputFile; v5+/v6: -Path/-Output). Invoke-Pester
reference). Keep changes small and reviewable — one file or one concern at a time.
Install-Module (Step 0), then re-import: Remove-Module Pester;Import-Module Pester (or start a fresh session).
-Output Detailed; use -Output Diagnostic (v4→v5) or read theexplicit v6 error messages to locate problems. Match each failure to the symptom → fix tables in the reference.
diff, then commit. Migrating in small commits makes regressions trivial to bisect.
| Jump | Difficulty | Nature | |---|---|---| | v3 → v4 | Low | Assertion-syntax rename (Should -Be). Largely script-automatable. | | v4 → v5 | High | New two-phase runtime. Test structure changes: setup must move into BeforeAll, discovery-time code into BeforeDiscovery, file location via $PSScriptRoot. Not a pure find-replace. | | v5 → v6 | Low–Medium | Backwards-compatible runtime; deprecated features now throw. Mostly small, targeted fixes. Your Should -Be assertions keep working unchanged. |
powershell# 1. Move file import into BeforeAll, use $PSScriptRoot (NOT $MyInvocation.MyCommand.Path) # BEFORE $here = Split-Path -Parent $MyInvocation.MyCommand.Path . "$here\Get-Thing.ps1" # AFTER BeforeAll { . $PSScriptRoot/Get-Thing.ps1 } # 2. Any code that DISCOVERS/generates tests must be in BeforeDiscovery BeforeDiscovery { $cases = Get-Content $PSScriptRoot/cases.json | ConvertFrom-Json } # 3. Should -Throw matches with -like wildcards, not .Contains { throw 'a long message' } | Should -Throw '*long*' # 4. Invoke-Pester legacy params → New-PesterConfiguration (see reference for full map)
Full details, scoping rules, and the parameter→config table: references/v4-to-v5.md.
powershell# 1. Mock assertions: removed verbs — rename (old -> new): # Assert-MockCalled -> Should -Invoke # Assert-VerifiableMock -> Should -InvokeVerifiable Should -Invoke Get-Thing -Times 1 -Exactly Should -InvokeVerifiable # 2. Add a default mock — unmatched calls no longer run the real command Mock Get-Thing { 'default' } Mock Get-Thing -ParameterFilter { $Name -eq 'a' } -MockWith { 'a' } # 3. Empty/$null -ForEach now throws; allow it only where empty is expected Describe 'Optional' -ForEach $cases -AllowNullOrEmptyForEach { } # 4. Combine duplicate BeforeAll/BeforeEach/AfterAll/AfterEach in the same block into one
Full breaking-change list with symptoms and fixes: references/v5-to-v6.md.
structured and invoked. If a test starts passing/failing differently for any reason other than a documented breaking change, investigate before accepting it.
references) help with Should syntax and dot-sourcing, but always review the diff and re-run the suite afterward. Never bulk-edit and commit unchecked.
*.Tests.ps1 — preserve the originalencoding (UTF-8 vs ASCII) so you don't mangle non-ASCII test names.
git bisect useful if amigrated test goes red later.
Other measured skills in the registry, with their headline benchmark lift.