Powershell

PSScriptAnalyzer: The Ultimate PowerShell Script Analyzer and Linter

Learn how to use PSScriptAnalyzer to improve code quality and identify issues in your PowerShell scripts and CI/CD pipelines

As you get more into DevOps and running CI/CD pipelines with PowerShell code, you will find that you want to have a way to check your code as the pipeline runs. PSScriptanalyzer is a free PowerShell module that provides the ability to check your PowerShell code in your pipelines for code quality and other issues. Let’s look at PSScriptAnalyzer and see how it is the ultimate linter for PowerShell code in CI/CD.

What does PSScriptAnalyzer do?

PSScriptAnalyzer is a PowerShell extension developed by the PowerShell team for use as a script analyzer for PowerShell script files and modules. It is a static code checker that scrutinizes PowerShell code to detect potential code defects in PowerShell files (using built-in rules), using best practices, and common syntax errors feedback. It helps developers improve the quality of their PowerShell scripts.

You can also use it as a stage in your CI/CD pipelines running PowerShell code to have the linting stage run before the code actually does anything in the environment. If errors or other bad code artifacts are detected, your CI/CD pipeline will fail the stage before it moves on to other aspects of the pipeline.

It then displays in its log output its findings. These allow the developer to check the recommendations and make sure these are corrected before rerunning the pipeline.

What does it check for?

There is a wide range of things the module checks for, and findings will result in informational warnings or error statuses. Note some examples of findings and guidelines you can receive with PSScriptAnalyzer and their severity to improve formatting, code performance and efficiency, security, and maintainability. You can find the full Microsoft documentation here: PSScriptAnalyzer Module – PowerShell | Microsoft Learn.

Informational

  • Use only Approved Verbs UseApprovedVerbs
  • Cmdlets names with unusable characters AvoidReservedCharInCmdlet
  • Parameter names that can’t be used AvoidReservedParams
  • Support confirmation requests UseShouldProcessForStateChangingFunctions and UseShouldProcessForStateChangingFunctions
  • Must call ShouldProcess when the ShouldProcess attribute is present and vice versa UseShouldProcess
  • Nouns should be singular UseSingularNouns
  • Missing module manifest fields MissingModuleManifestField
    • Version
    • Author
    • Description
    • LicenseUri (for PowerShell Gallery)
  • Switch parameters shouldn’t default to true AvoidDefaultValueSwitchParameter

Warning

  • Avoid using aliases AvoidUsingCmdletAliases
  • Avoid using Write-host
  • Avoid using uninitialized variables
  • Avoid using deprecated WMI cmdlets AvoidUsingWMICmdlet
  • Avoid using empty catch blocks AvoidUsingEmptyCatchBlock
  • Invoke existing cmdlets with correct parameters UseCmdletCorrectly
  • Cmdlets should have ShouldProcess/ShouldContinue and Force parameter if using certain system-modifying verbs (Update, Set, Remove, New): UseShouldProcessForStateChangingFunctions
  • Avoid using positional parameters AvoidUsingPositionalParameters
  • Avoid using global variables AvoidGlobalVars
  • Declared variables should be used after their assignment UseDeclaredVarsMoreThanAssignments
  • Avoid using Invoke-Expression AvoidUsingInvokeExpression

Error

  • Avoid using plain text passwords AvoidUsingPlainTextForPassword
  • Avoid -Username and -Password parameters (use PSCredential instead): UsePSCredentialType
  • Avoid hardcoding a -ComputerName parameter argument (information disclosure): AvoidUsingComputerNameHardcoded
  • Avoid using ConvertTo-SecureString with plaintext (information disclosure): AvoidUsingConvertToSecureStringWithPlainText

Installation and Getting Started

To install PSScriptAnalyzer, we can use the Install-Module command. You can use this command in either Windows PowerShell or PowerShell Core.

As an example, to install the module, we can use the following command:

Install-Module PSScriptAnalyzer
Running the install module command for psscriptanalyzer
Running the install module command for psscriptanalyzer

In the above, we are forcing the installation and setting the scope to be available for all users. If you need to you can also use additional parameters:

Install-Module PSScriptAnalyzer -Force -Scope AllUsers -AllowClobber
Setting the scope and allow clobber for the installation
Setting the scope and allow clobber for the installation

The “allowclobber” parameter overrides warnings about installation conflicts. And then we can skip the publisher check.

Using PSScriptAnalyzer with Invoke-ScriptAnalyzer

The simple way to use the new PSScriptAnalyzer module is using the cmdlet:

Invoke-ScriptAnalyzer

To point the PSScriptAnalyzer to a PowerShell file, we can use the “-Path” parameter to specify where the PowerShell script is located.

Invoke-ScriptAnalyzer -Path powershellscript.ps1

Using the Recurse parameter

Another cool thing we can do is use the recurse parameter. With this parameter, it makes checking a large number of PowerShell script much easier. When you use the -Recurse parameter with the -Path parameter, it tells ScriptAnalyzer to not only analyze the scripts located directly at the path specified, but also to recursively analyze all scripts found in all subdirectories under that path

Using PSScriptAnalyzer in CI/CD

The power of PSScriptAnalyzer really comes into play with CI/CD pipelines if you are using PowerShell scripts for automation. You can integrate it as a stage in your CI/CD pipeline process and automate the analysis of PowerShell scripts at every code check-in. Below, you can see the output of a Gitlab pipeline I am using with PSScriptAnalyzer checks with best practices identified in the diagnosticresults below.

Viewing the job failure due to psscriptanalyzer results
Viewing the job failure due to psscriptanalyzer results

Below is a run with even more output and recommended improvements to review as documentation, including uninitialized variables use, trailing whitespace, and aliases used:

Large list of psscriptanalyzer results 1
Large list of psscriptanalyzer results 1

This helps to make sure that every piece of code is scrutinized for issues before it is deployed which increases the quality of PowerShell code and leads to more stable and secure applications. 

Lint stage failed in the ci cd pipeline 1
Lint stage failed in the ci cd pipeline 1

Adding PSScriptAnalyzer to a pipeline

How exactly do you add PSScriptAnalyzer to a pipeline? Well there are a few ways to do it. If you just want to run the PSScriptAnalyzer with all the checks and fail your pipeline on any type of message back, including informational, you can do something like the following in your gitlab-ci.yml file:

image:
  name: vmware/powerclicore

before_script:
- apt-get update
- apt-get install -y smbclient
# Install PowerShell ScriptAnalyzer
- pwsh -Command "if (-not (Get-Module -ListAvailable -Name PSScriptAnalyzer)) { Install-Module PSScriptAnalyzer -Force -Scope AllUsers }"

stages:
- lint
- deploy

lint_powershell_script:
stage: lint
script:
# Run PowerShell Script Analyzer
- pwsh -Command "Invoke-ScriptAnalyzer -Path myscript.ps1 -Recurse

powercliscript:
stage: deploy
script:
- pwsh -File myscript.ps1

If you want to fail your pipeline for only “warning” and “error” messages from PSScriptAnalyzer, you can do this. Notice the lint stage is now calling a separate script for lining.

image:
name: vmware/powerclicore

before_script:
- apt-get update
- apt-get install -y smbclient

stages:
- lint
- deploy

lint_powershell_script:
stage: lint
script:
- pwsh -File run_psscriptanalyzer.ps1
allow_failure: false
only:
- main

powercliscript:
stage: deploy
script:
- pwsh -File poweredonvms.ps1
only:
- main

The contents of the run_psscriptanalyzer.ps1 script is the following:

Install-Module PSScriptAnalyzer -Force -Scope AllUsers -AllowClobber -SkipPublisherCheck

$analysisResults = Invoke-ScriptAnalyzer -Path poweredonvms.ps1 -Recurse
if ($analysisResults) {
    $analysisResults | Format-Table | Out-String -Width 120 | Write-Output
    $errorsAndWarnings = $analysisResults | Where-Object { $_.Severity -eq 'Error' -or $_.Severity -eq 'Warning' }
    if ($errorsAndWarnings) {
        exit 1
    }
}

As you can see above, we refer to the PowerShell script checks as linting. What is it?

What is a linter?

A linter is a tool that analyzes source code to flag programming errors, bugs, style errors, and any less-than-desirable code. It helps enforce coding standards and improves code quality before it ships. It does this by identifying potential issues before the code is executed or compiled. 

Linters are available for many programming languages, each tailored to the specific syntax for that particular programming language. By integrating a linter into the development process, you can catch and correct problems early, rather than having them make it into production. This helps ensure more reliable and maintainable code.

Customizing Rules for Your Needs

One of the strengths of PSScriptAnalyzer is the ability to customize and use it as you need for your particular environments. Users can enable, disable, or even create custom rules to suit their specific project requirements. It allows teams to inform users of their own coding standards and practices.

There is a special cmdlet that is part of the module to view the ScriptAnalyzer rules. You can use the cmlet:

Get-ScriptAnalyzerRule

It allows you to see which rules are checked and detailed information about each rule.

Get scriptanalyzerrule 1
Get scriptanalyzerrule

You can also as we did above, return the outputs that you want and send this back to the pipeline. This allows you to stop the pipeline based on certain messages returned in the script analysis.

Wrapping up PSScriptAnalyzer

PSScriptAnalyzer is a great tool for making sure your PowerShell code is clean and without issues before it is used in production. It can be used as a standalone checker or integrated into your CI/CD pipeline solutions. PSScriptAnalyzer helps developers make sure their PowerShell scripts are secure and aligned with best practices standards.

Even in the home lab environment, it is a great way to start looking at the quality of scripts you may be using and implement CI/CD pipelines to automate workflows in your lab to make things easier and more secure and learn more DevOps skills to carry into production.

Subscribe to VirtualizationHowto via Email 🔔

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Brandon Lee

Brandon Lee is the Senior Writer, Engineer and owner at Virtualizationhowto.com and has over two decades of experience in Information Technology. Having worked for numerous Fortune 500 companies as well as in various industries, Brandon has extensive experience in various IT segments and is a strong advocate for open source technologies. Brandon holds many industry certifications, loves the outdoors and spending time with family.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.