Lint PowerShell scripts with PSScriptAnalyzer 🐢
Tags: codequality, powershell, code, gitlab
Published: 2021-03-05 19:23:27

---
title: Lint PowerShell scripts with PSScriptAnalyzer 🐢
published: true
date: 2021-02-26 00:15:00 UTC
tags: codequality, powershell, code, gitlab
canonical_url: https://www.benjaminrancourt.ca/lint-powershell-scripts-with-psscriptanalyzer
cover_image: https://www.benjaminrancourt.ca/temp/lint-powershell-scripts-with-psscriptanalyzer.1354.jpg
---
If you are a Windows developer, you may write **PowerShell scripts** , especially if you interact with some Windows product, like [AD FS](https://docs.microsoft.com/en-us/windows-server/identity/active-directory-federation-services). Recently, I had to rightfully write a script in PowerShell to [create a Relying Party Trust](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/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](https://github.com/PowerShell/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](https://gitlab.com/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](https://docs.gitlab.com/runner/install/). Therefore, the new image must run on a Linux runner.

```docker
# 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"]
```

## 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.

```yaml
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
```

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.
```

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