Stefan Stranger's Blog

Use Azure DevOps Pipeline to Publish a PowerShell Module to the PowerShell Gallery

2018-12-30 00:00:00 +0000 ·

Recently I released a new PowerShell Module called PSJwt to the PowerShell Gallery. This is a PowerShell Module for JWT (JSON Web Tokens). The PowerShell Module is using the Jwt.Net library. This library supports generating and decoding JSON Web Tokens.

Part of the code for this PowerShell Module are the build steps and Azure DevOps YAML Build Pipeline.

In this blog post I explain how to use an Azure DevOps YAML Build Pipeline to Publish your PowerShell Module to the PowerShell Gallery.

Build Steps

For the Build Steps I used the Invoke-Build PowerShell Module from Roman Kuzmin.

Invoke-Build/InvokeBuild is a build and test automation tool which invokes tasks defined in PowerShell v2.0+ scripts. It is similar to psake but according to Roman easier to use and more powerful. It is complete, bug free, well covered by tests.

Install InvokeBuild Module

Run:

Install-Module -Name InvokeBuild -scope CurrentUser

And when you use Visual Studio Code I recommend you to also install the following helper PowerShell scripts:

  • Invoke-TaskFromVSCode.ps1 - invokes a task from a build script opened in VSCode
  • New-VSCodeTask.ps1 - generates VSCode tasks bound to build script tasks
Install-Script -Name Invoke-TaskFromVSCode
Install-Script -Name New-VSCodeTask

For development of the PowerShell Module I created the following tasks in the PSJwt.build.ps1 script:

  1. Task to Update the PowerShell Module Help Files
  2. Task to retrieve latest version of JWT Packages
  3. Task to Update JWT Package if newer version is released
  4. Task to Copy PowerShell Module files to output folder for release as Module
  5. Task to run all Pester tests in folder .\tests
  6. Task to update the Module Manifest file with info from the Changelog in Readme
  7. Task to Publish Module to PowerShell Gallery
  8. Task clean up Output folder

Note:

Not all the task defined in the Build script will be used in the Azure DevOps Build Pipeline.
We'll be using the following tasks in the Build Pipeline:
* Clean
* Copy PowerShell Modules files to output folder
* Publish Module to PowerShell Gallery

Publish to PowerShell Gallery Task

For Publishing the PowerShell Module we need to use the PowerShell Cmdlet Publish-Module from the PowerShellGet PowerShell Module.

PublishModule InvokeBuild Task code:

task PublishModule -If ($Configuration -eq 'Production') {
    Try {
        # Build a splat containing the required details and make sure to Stop for errors which will trigger the catch
        $params = @{
            Path        = ('{0}\Output\PSJwt' -f $PSScriptRoot )
            NuGetApiKey = $env:psgallery
            ErrorAction = 'Stop'
        }
        Publish-Module @params
        Write-Output -InputObject ('PSJwt PowerShell Module version published to the PowerShell Gallery')
    }
    Catch {
        throw $_
    }
}

I added a parameter to the PSJwt.build.ps1 script to manage when the PowerShell Module should be publised to the Gallery.

If you call the task as follows the module will be published to the PowerShell Gallery:

Invoke-Build -Configuration 'Production' -Task PublishModule

The PowerShell Gallery API Key is stored as an Environment variable called PSGallery. On your local system you can create the environment variable as follows.

[Environment]::SetEnvironmentVariable('PSGallery', '[enter here PowerShell Gallery API Key]', 'User'

On the Azure DevOps (Build) Agent we will use a variable (NuGetAPIKey) to configure the PowerShell Gallery API Key.

Azure DevOps Build Pipeline

Azure Pipelines is a cloud service that you can use to automatically build and test your code project and make it available to other users. It works with just about any language or project type.

Azure Pipelines combines continuous integration (CI) and continuous delivery (CD) to constantly and consistently test and build your code and ship it to any target.

Last year Microsoft introduced YAML builds to give you another option for defining and evolving your continuous integration builds as your code evolves. I defined my Azure DevOps Build Pipeline in a YAML file, part of the code in my Github Repository.

During the Build I want to execute some of the tasks I defined in my Invoke-Build script PSJwt.build.ps1 and that is why I need to do some pre-requisites tasks like installing PowerShell Modules (InvokeBuild) before I can call the Invoke-Build PowerShell Function.

Let’s have a look at the azure-pipelines.yml file:

# Docs: https://aka.ms/yaml
name: $(Build.DefinitionName)_$(Date:yyyyMMdd))
pr:
- master

queue:
  name: Hosted VS2017

steps:
- powershell: .\bootstrap.ps1
  displayName: 'Install pre-requisites'

- task: richardfennellBM.BM-VSTS-PesterRunner-Task.Pester-Task.Pester@8
  displayName: 'Pester Test Runner'
  inputs:
    scriptFolder: '$(System.DefaultWorkingDirectory)\tests\*'
    additionalModulePath: '$(Build.ArtifactStagingDirectory)'
    resultsFile: '$(Common.TestResultsDirectory)\Test-$(Build.DefinitionName)_$(Build.BuildNumber).xml'

- task: PublishTestResults@2
  displayName: 'Publish Test Results'
  condition: always()
  inputs:
    testRunner: NUnit
    searchFolder: '$(Common.TestResultsDirectory)'

- powershell: Invoke-Build -Configuration 'Production' -Task Clean, CopyModuleFiles, PublishModule
  displayName: 'Publish PowerShell Module'
  env:
    psgallery: $(NugetAPIKey)

The following code defines the type of (Build) Agent where the build taks will be run on. In this case a Hosted VS2017 Agent.

queue:
  name: Hosted VS2017

The next task in the Build will use the PowerShell Task to run the pre-requisites PowerShell script (bootstrap.ps1) which installs the following PowerShell modules, InvokeBuild, Pester and PlatyPS.

I found this bootstrap script solution on Joel Bennett’s PTUI Github Repository.

- powershell: .\bootstrap.ps1
  displayName: 'Install pre-requisites'

The nexts tasks will run the Pester Tests using Richard Fennell’s Pester Test Runner Build Task. This time I’m not using the Test task from my own build script, but you could also use the Test Task from my Build script if you wanted. I choose Richard’s Task because it creates a results file which is used in the next task to publish the test results.

- task: richardfennellBM.BM-VSTS-PesterRunner-Task.Pester-Task.Pester@8
  displayName: 'Pester Test Runner'
  inputs:
    scriptFolder: '$(System.DefaultWorkingDirectory)\tests\*'
    additionalModulePath: '$(Build.ArtifactStagingDirectory)'
    resultsFile: '$(Common.TestResultsDirectory)\Test-$(Build.DefinitionName)_$(Build.BuildNumber).xml'

- task: PublishTestResults@2
  displayName: 'Publish Test Results'
  condition: always()
  inputs:
    testRunner: NUnit
    searchFolder: '$(Common.TestResultsDirectory)'

With the last task the Invoke-Build script (PSJwt.build.ps1) is run on the Build Agent. The tasks Clean, CopyModuleFiles and PublishMode are executed.

- powershell: Invoke-Build -Configuration 'Production' -Task Clean, CopyModuleFiles, PublishModule
  displayName: 'Publish PowerShell Module'
  env:
    psgallery: $(NugetAPIKey)

Note:

You also need to define a Azure DevOps variable which contains your PowerShell Gallery NugetAPIKey value.

Azure DevOps Variable

The NugetAPIKey variable will be configured as an environment variable which will be used during the PublishModule Build Task.

Build Trigger

I want to trigger the Build and the Publish PowerShell Module task only for the Master Branch and when the PowerShell Module Manifest file is commited to the Github Repository.

Azure DevOps Variable

Above configuration triggers the Build when a new Module Manifest (PSJwt.psd1) commit is made. All other file commits don’t trigger a new build.

PowerShell Gallery Result

Hope this inspired you to use Azure DevOps YAML Pipelines to publish your PowerShell Modules to the PowerShell Gallery.

References:

  • PSJwt PowerShell Module on PowerShel Gallery
  • Github Repository for PSJwt
  • InvokeBuild PowerShell Module on PowerShell Gallery
  • Github Repository for Invoke-Build PowerShell Module
  • Create your first pipeline
  • YAML schema reference
  • Pester Test Runner Build Task
  • PSake PowerShell Module on Github








  • About
  • Contact
  • Search
  • Powered by Jekyll using the Trio theme