Invoking PSScriptAnalyzer in Pester Tests for each Rule

Ryan YatesConsultant

Just a dude in his 30's doing things in Tech & trying to break the stigma's around talking about Mental Health

This is a quick walkthrough on how you can get output from PSScriptAnalyzer rules in your Pester tests.

So you’ll need

  • Pester ( Version 3.4.0 or above )
  • PSScriptAnalyzer ( Version 1.4.0 or above )

Please note this is shown running on PowerShell  v5 as part of Windows 10 Build 14295 – results may vary on other PowerShell Versions

In the nature of the way we want to work we may have new ScriptAnalyzer rules in the near future (new version / additional community additions / your own custom ScriptAnalyzer rules etc) and we would want ensure that we test for them all without having to change much of the below code

to dynamically do this within our Context Block.

So our example code in our Pester Test would look like this

#Script#PesterScriptAnalzyerExample#
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path
$Scripts = Get-ChildItem "$here" -Filter '*.ps1' -Recurse | Where-Object {$_.name -NotMatch 'Tests.ps1'}

$Modules = Get-ChildItem "$here" -Filter '*.psm1' -Recurse
$Rules = Get-ScriptAnalyzerRule

Describe 'Testing all Modules in this Repo to be be correctly formatted' {

    foreach ($module in $modules) {

        Context "Testing Module  - $($module.BaseName) for Standard Processing" {

            foreach ($rule in $rules) {

                It "passes the PSScriptAnalyzer Rule $rule" {

                    (Invoke-ScriptAnalyzer -Path $module.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0

                }

            }

        }

    }

}

Describe 'Testing all Scripts in this Repo to be be correctly formatted' {

    foreach ($Script in $scripts) {

        Context "Testing Module  - $($script.BaseName) for Standard Processing" {

            foreach ($rule in $rules) {

                It "passes the PSScriptAnalyzer Rule $rule" {

                    (Invoke-ScriptAnalyzer -Path $script.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0

                }

            }

        }

    }

And the result that we would get would be the below

PS C:\Users\Ryan\OneDrive\GitHub\kilasuit\Scripts-WIP\PesterScriptAnalzyerExample> .\PesterScriptAnalzyerExample.ps1

Describing Testing all Modules in this Repo to be be correctly formatted

Describing Testing all Scripts in this Repo to be be correctly formatted

 Context Testing Module  - PesterScriptAnalzyerExample for Standard Processing

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingCmdletAliases 233ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidDefaultValueSwitchParameter 124ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingEmptyCatchBlock 134ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidGlobalVars 87ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidInvokingEmptyMembers 104ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidNullOrEmptyHelpMessageAttribute 70ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingPositionalParameters 879ms

 [+] passes the PSScriptAnalyzer Rule PSReservedCmdletChar 75ms

 [+] passes the PSScriptAnalyzer Rule PSReservedParams 81ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidShouldContinueWithoutForce 85ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingDeprecatedManifestFields 117ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidDefaultValueForMandatoryParameter 123ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingUserNameAndPassWordParams 95ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingComputerNameHardcoded 113ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingConvertToSecureStringWithPlainText 98ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingInvokeExpression 75ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingPlainTextForPassword 103ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingWMICmdlet 138ms

 [+] passes the PSScriptAnalyzer Rule PSAvoidUsingWriteHost 91ms

 [+] passes the PSScriptAnalyzer Rule PSMisleadingBacktick 100ms

 [+] passes the PSScriptAnalyzer Rule PSUseBOMForUnicodeEncodedFile 100ms

 [+] passes the PSScriptAnalyzer Rule PSUseToExportFieldsInManifest 87ms

 [+] passes the PSScriptAnalyzer Rule PSUseOutputTypeCorrectly 128ms

 [+] passes the PSScriptAnalyzer Rule PSMissingModuleManifestField 84ms

 [+] passes the PSScriptAnalyzer Rule PSPossibleIncorrectComparisonWithNull 99ms

 [+] passes the PSScriptAnalyzer Rule PSProvideCommentHelp 98ms

 [+] passes the PSScriptAnalyzer Rule PSUseApprovedVerbs 75ms

 [+] passes the PSScriptAnalyzer Rule PSUseCmdletCorrectly 867ms

 [+] passes the PSScriptAnalyzer Rule PSUseDeclaredVarsMoreThanAssigments 82ms

 [+] passes the PSScriptAnalyzer Rule PSUsePSCredentialType 91ms

 [+] passes the PSScriptAnalyzer Rule PSShouldProcess 160ms

 [+] passes the PSScriptAnalyzer Rule PSUseShouldProcessForStateChangingFunctions 86ms

 [+] passes the PSScriptAnalyzer Rule PSUseSingularNouns 177ms

 [+] passes the PSScriptAnalyzer Rule PSUseUTF8EncodingForHelpFile 176ms

 [+] passes the PSScriptAnalyzer Rule PSDSCDscTestsPresent 98ms

 [+] passes the PSScriptAnalyzer Rule PSDSCDscExamplesPresent 102ms

 [+] passes the PSScriptAnalyzer Rule PSDSCUseVerboseMessageInDSCResource 81ms

 [+] passes the PSScriptAnalyzer Rule PSDSCUseIdenticalMandatoryParametersForDSC 110ms

 [+] passes the PSScriptAnalyzer Rule PSDSCUseIdenticalParametersForDSC 74ms

 [+] passes the PSScriptAnalyzer Rule PSDSCStandardDSCFunctionsInResource 122ms

 [+] passes the PSScriptAnalyzer Rule PSDSCReturnCorrectTypesForDSCFunctions 101ms

 

This allows you to see from your test if it fails or not and as shown is able to be used for scripts and modules.

The example is a good example as well of getting Pester to test your Pester tests Winking smile

This example is being added into ISE_Cew (see post) in the next feature release (next week some point) though you can just copy and paste it from this blog post as well thanks to a PowerShell ISE addon called CopytoHtml by Gary Lapointe in which you can find more about it and download it at http://blog.falchionconsulting.com/index.php/2012/10/Windows-PowerShell-V3-ISE-Copy-As-HTML-Add-On/

Please note that although the above works fine – I dont see the point in running the Describe block if the tests below wont run so I’m adding what I think to be the better version below – this will only run the Describe blocks if there is any scripts or modules

#Script#PesterScriptAnalzyerExample#

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

$Scripts = Get-ChildItem "$here" -Filter '*.ps1' -Recurse | Where-Object {$_.name -NotMatch 'Tests.ps1'}

$Modules = Get-ChildItem "$here" -Filter '*.psm1' -Recurse

$Rules = Get-ScriptAnalyzerRule

if ($Modules.count -gt 0) {

 Describe 'Testing all Modules in this Repo to be be correctly formatted' {

 foreach ($module in $modules) {

 Context "Testing Module  - $($module.BaseName) for Standard Processing" {

 foreach ($rule in $rules) {

 It "passes the PSScriptAnalyzer Rule $rule" {

 (Invoke-ScriptAnalyzer -Path $module.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0

 }

 }

 }

 }

 }

}

if ($Scripts.count -gt 0) {

 Describe 'Testing all Scripts in this Repo to be be correctly formatted' {

 foreach ($Script in $scripts) {

 Context "Testing Module  - $($script.BaseName) for Standard Processing" {

 foreach ($rule in $rules) {

 It "passes the PSScriptAnalyzer Rule $rule" {

 (Invoke-ScriptAnalyzer -Path $script.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0

 }

 }

 }

 }

 }

}