February 2nd, 2017

PSScriptAnalyzer deep dive – Part 3 of 4

Doctor Scripto
Scripter

Summary: Thomas Rayner, Microsoft Cloud and Datacenter Management MVP, shows how to use Pester to get nUnit formatted results out of PSScriptAnalyzer.

Hello! I’m Thomas Rayner, a Cloud and Datacenter Management Microsoft MVP, filling in for The Scripting Guy this week. You can find me on Twitter (@MrThomasRayner), or posting on my blog, workingsysadmin.com. This week, I’m presenting a four-part series about how to use PSScriptAnalyzer.

Part 1 – Getting started with PSScriptAnalyzer

Part 2 – Suppressing, including, excluding rules

Part 3 – Wrapping PSScriptAnalyzer with Pester to get formatted results

Part 4 – Writing custom rules

This is Part 3, and I’m going to show you how to get nUnit formatted results from PSScriptAnalyzer.

nUnit is an XML based open source test result format. nUnit is a testing format that’s used in popular Continuous Integration and Continuous Deployment services like AppVeyor and Visual Studio Team Services. There are ways to get differently formatted and recorded output from PSScriptAnalyzer. By default, most people I’ve worked with have found it easiest to use Pester to format their test results.

Pester is a domain-specific language that was developed to test PowerShell code. There are a ton of great resources to learn Pester. If what you see in this post is very unfamiliar, I’d recommend finding a book, online training course, blog, or other resource to get started. The Pester GitHub page is a great place to start.

Note: Procedures in this post are for Pester version 3.4.6 and haven’t been tested on 4.x yet.

If you don’t already have Pester installed, you can get it from the PowerShell Gallery and import the module.

Install-Module -Name Pester -Scope CurrentUser

Import-Module -Name Pester

Now you’re ready to do some Pester testing.

First, let’s define the script, named MyScript.ps1, that we want to evaluate.

param (

$Path, $DaysOld

) $someVar = $null Write-Host "Counting items..." $itemCount = (gci $Path | ? { $_.LastWriteTime -gt (Get-Date).AddDays(-$DaysOld)}).Count Write-Host "There are $itemCount items"

There are some clear problems with this already, but, if it were perfect, it wouldn’t generate interesting PSSA output.

Now, I’m going to write a Pester test. I’ll start by declaring a Describe and Context block.

Describe 'Testing against PSSA rules' {

Context 'PSSA Standard Rules' {

}

}

Now, something should probably go inside, right? I’m going to run PSSA against my script, store the variables in $analysis, and get a list of rules stored in $scriptAnalyzerRules. (I could also specify a location to custom rules here if I had any.)

$analysis = Invoke-ScriptAnalyzer -Path '.\MyScript.ps1'

$scriptAnalyzerRules = Get-ScriptAnalyzerRule

Why did I do this? What I’m going to do next is use a foreach loop to build all my It statements, and test for all the rules we’re evaluating.

forEach ($rule in $scriptAnalyzerRules) {

It "Should pass $rule" {

If ($analysis.RuleName -contains $rule) {

$analysis |

Where RuleName -EQ $rule -outvariable failures | Out-Default

$failures.Count | Should Be 0

}

}

}

Here, I’m looping through all the rules that PSSA checked and declaring that my script should pass that rule. Any PSSA rule violations are stored in $analysis. So, if $analysis.RuleName has an entry in it that matches a rule, I know that this assertion failed.

Here’s what my full test file, MyTest.tests.ps1, looks like.

Describe 'Testing against PSSA rules' {

Context 'PSSA Standard Rules' {

$analysis = Invoke-ScriptAnalyzer -Path  '.\MyScript.ps1'

$scriptAnalyzerRules = Get-ScriptAnalyzerRule

forEach ($rule in $scriptAnalyzerRules) {

It "Should pass $rule" {

If ($analysis.RuleName -contains $rule) {

$analysis |

Where RuleName -EQ $rule -outvariable failures | Out-Default

$failures.Count | Should Be 0

}

}

}

}

}

Now, I just need to run one line to get my nUnit formatted test results.

Invoke-Pester -OutputFile 'PSSAResults.xml' -OutputFormat 'LegacyNUnitXml' -Script '.\MyTest.tests.ps1'

Done! Presumably, if you’re doing this, it’s to interface with some Continuous Integration/Deployment service like AppVeyor or Visual Studio Team Services. You will have a couple steps left to integrate this solution seamlessly into your Continuous Integration/Deployment suite of choice to properly collect and act on the test results. This is the funky part – getting nUnit formatted results from PSSA.

There are other ways to get the same result, but this is a pretty easy, scalable solution that I happen to like. If it doesn’t work for you for some reason, I’d love to hear about your alternative!

Now, if you’ve integrated this into Visual Studio Team Services, for example, you’ll get some cool screens like these:

Looking at the test results in Visual Studio Team Services.

Build results that include Pester results

Reviewing detailed results for the PSSA results to see which rules were violated.

Pass / fail results

I have a much longer post on my blog that explains how to set this up Visual Studio Team Services. If that interests you, feel free to check out Invoking Pester and PSScriptAnalyzer Tests in Hosted VSTS.

Come back tomorrow, and I’m going to show you how to write your own customized PSScriptAnalyzer rules.

Thomas, thanks for that update!  Using Pester as an addition tool is certainly an excellent way to QA my tools before going into production!

I invite you to follow the Scripting Guys on Twitter and Facebook. If you have any questions, send email to them at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow.

Until then, always remember that with Great PowerShell comes Great Responsibility.

Sean Kearney Honorary Scripting Guy Cloud and Datacenter Management MVP

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.