DEV Community

Cover image for Lint PowerShell scripts with PSScriptAnalyzer 🐢
Benjamin Rancourt
Benjamin Rancourt

Posted on • Originally published at benjaminrancourt.ca on

Lint PowerShell scripts with PSScriptAnalyzer 🐢

If you are a Windows developer, you may write PowerShell scripts , especially if you interact with some Windows product, like AD FS. Recently, I had to rightfully write a script in PowerShell to create a Relying Party Trust into AD FS. But after writing it, I was wondering if I could lint my code to make sure it was written correctly. So, I started looking for a PowerShell linter and I found one: PSScriptAnalyzer. 🐚

PSScriptAnalyzer is a tool written by the Microsoft PowerShell Team to ensure that your PowerShell modules and script follow the best practices identified by them and the community. I tried it on my scripts and the tool gave warnings on some Write-Host commands that I initially had in my code. Since I did not want to run it manually each time I made a change, I started to check if I could add the tool inside our GitLab pipeline. ⚗️

Unfortunately for me, I could not find a code that I could simply plug and play in my pipeline. I have found a GitLab project named 4x0v7/psscriptanalyzer-docker that had a Dockerfile with the tool installed and a GitLab pipeline, but it did not seem to have a real example of how to use it. I think it was by running a docker run command, but I was reluctant to use it that way. So I started experimenting to see if I could improve it and execute the commands directly in the native command-line shell.

After too many failed attempts, I have found a recipe that is not yet perfect, but since it did the job, I want to share it in case others need it. 😉

Dockerfile

The following Dockerfile uses a Linux image and is built by a Linux runner. Therefore, the new image must run on a Linux runner.

# https://hub.docker.com/_/microsoft-powershell
FROM mcr.microsoft.com/powershell:lts-debian-buster-slim-20210125

# Change the shell to use Powershell directly for our commands
# instead of englobing them with pwsh -Command "MY_COMMAND"
SHELL ["pwsh", "-Command"]

RUN \
    # Sets values for a registered module repository
    Set-PSRepository \
      -ErrorAction Stop <# Action to take if a command fails #> \
      -InstallationPolicy Trusted <# Installation policy (Trusted, Untrusted) #> \
      -Name PSGallery <# Name of the repository #> \
      -Verbose; <# Write verbose output #> \
    # Install PSScriptAnalyzer module (https://github.com/PowerShell/PSScriptAnalyzer/tags)
    Install-Module \
      -ErrorAction Stop \
      -Name PSScriptAnalyzer <# Name of modules to install from the online gallery #> \
      -RequiredVersion 1.19.1 <# Exact version of a single module to install #> \
      -Verbose;

# Switch back to the default Linux shell as we are using a Linux Docker image for now
SHELL ["/bin/sh" , "-c"]
Enter fullscreen mode Exit fullscreen mode

GitLab CI

The following step inside the .gitlab-ci.yml uses an image generated from the previous Dockerfile. I did not include the generation of the image so as not to overload this post.

ps-script-analyzer:
  before_script:
    # Show the PowerShell version
    - pwsh -Version
  image: ${CI_REGISTRY_IMAGE}:latest
  script:
    # Execute recursively the analyzer
    - pwsh -Command "Invoke-ScriptAnalyzer -EnableExit -Recurse -Path ."
  stage: lint
Enter fullscreen mode Exit fullscreen mode

If the tool reports any issues, it will generate a message like below. I find it is not very readable, but at least, it is better than nothing. 🤔

RuleName Severity ScriptName Line Message
------------- -------- ---------- ---- -------
PSAvoidUsingWriteHost Warning test.ps1 1 File
                                                                  'test.ps1'
                                                                  uses
                                                                  Write-Host.
                                                                  Avoid using
                                                                  Write-Host
                                                                  because it
                                                                  might not
                                                                  work in all
                                                                  hosts, does
                                                                  not work
                                                                  when there
                                                                  is no host,
                                                                  and (prior
                                                                  to PS 5.0)
                                                                  cannot be
                                                                  suppressed,
                                                                  captured, or
                                                                  redirected.
                                                                  Instead, use
                                                                  Write-Output,
                                                                   Write-Verbos
                                                                  e, or Write-I
                                                                  nformation.
Enter fullscreen mode Exit fullscreen mode

If you have any tips for improving this part of the pipeline, let me know! 🕊️

Top comments (0)