1

I want to understand if it is possible to install/import a custom module and have its functions available for multiple Azure Powershell Tasks within the same Azure DevOps release pipeline stage.

Background

  • I have a custom powershell module (written by myself) that is packaged correctly into a nuget package by an Azure DevOps Build pipeline. This is stored in Azure Artifacts.

  • I reference this Azure Artifacts Powershell module in the Release pipeline and when run, the pipeline extracts correctly and I can see all the expected powershell scripts within the $Agent.ReleaseDirectory

  • In the DevOps Release pipeline Stage I have two tasks

    • Task 1) An initialisation Azure Powershell task intended to load the module and make the module functions available to the session and therefore available to later Azure Powershell tasks.
    • Task 2) A 'test' Azure Powershell task that calls a "Get-BuildNumber" powershell function that is part of the module.

The Problem

  • If I call "Get-BuildNumber" from Task 1 (that loads the module) then I get back my build number correctly. A write-host command confirms the value is correct.
  • If I call "Get-BuildNumber" from Task 2 (the one that tests the functions are available) then I get the response

The term 'Get-BuildNumber' is not recognized as the name of a cmdlet, function, script file, or operable program.

Analysis

  • It appears that the imported module is scoped to a single azure powershell task but I'd rather not have to load the module for each task.
  • I'm using the following commands in task 1 and the module itself 'dot sources' the script functions, making each function available in the session scope. On my local machine this all works correctly.
$currentDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Import-Module (Join-Path $currentDir "modules\deploy") -Force
$env:PSUTILSPATH = (Join-Path $currentDir "modules")

The deploy.psm1 module file just contains the following

$functions = Get-ChildItem -Recurse $PSScriptRoot  -Include *.ps1 | ? { $_ -notmatch ".Tests.ps1" }

foreach ($function in $functions) 
{
    . $function.FullName
}
  • Should I use Install-Module rather than Import-Module?
  • Maybe I need to import the module for each powershell task rather than attempting to load it once and reference many times?

Any help would be much appreciated.

4
  • Hi there, may I assume you were referencing the steps in this document to retrieve PS module package from your Azure Artifact feed? Where were the custom PS module files installed? Can you please check by this command tree "C:\Program Files\WindowsPowerShell\Modules" /F /A? It is one of the path of $PSModulePath. Could you specify your steps/script to get the custom module files? Commented Dec 20, 2023 at 11:50
  • Hi Alvin, I haven't read that document specifically. The deploy.psm1 file selects all files of type ps1 and then dot sources each one so that each one is available to the session. Commented Dec 20, 2023 at 14:00
  • Hi Alvin, thank you for responding. I've not read that document specifically. The Tree command doesn't show it as installed. The psm1 module file is imported and gets a list of ps1 files recursively, and for each file just dot sources it, to load the function into the session. I'm guessing that each Powershell pipeline task gets its own session which is why currently it is only visible in the task that imports the module. Commented Dec 20, 2023 at 14:57
  • Hi @SJB, Have you got a chance to check my workaround below? I generated a very simple PS module, packed & pushed to Azure Artifacts feed, and used the build-in feature of a release pipeline to retrieve the modules onto pipeline agent. Hope the method helps. Commented Dec 29, 2023 at 5:05

1 Answer 1

1

As far as I understand your requirement is to import a custom module for only one time, so that the subsequent Azure PowerShell task(s) doesn't have to import the module ever again.

I have tested with several methods, while only the trick below works. The workaround is to copy the custom module into the path C:\Program Files\WindowsPowerShell\Modules which is one of the path of $PSModulePath.

  1. I pushed my sample module Get-Hello to my Azure Artifacts feed as a private PowerShell repository; enter image description here
  2. The package was consumed as an artifact in my release pipeline; enter image description here
  3. With the help of simple PowerShell task, we could easily check the downloaded artifact files;
    Write-Host "1. Show file structure in System.DefaultWorkingDirectory and list the downloaded artifacts:"
    tree $(System.DefaultWorkingDirectory) /F /A
    
    Write-Host "2. Show PSModulePath:"
    $env:PSModulePath -split ';'
    
    enter image description here
  4. I used the CopyFiles@2 to copy the Get-Help (Source alias) directory together with the required module files in it into the target path C:\Program Files\WindowsPowerShell\Modules; enter image description here
  5. I could then proceed to use this custom function in the subsequent Azure PowerShell Task. enter image description here

According to this document, How to Write a PowerShell Script Module - PowerShell | Microsoft Learn

Starting with PowerShell 3.0, if you've placed your module in one of the PowerShell module paths, you don't need to explicitly import it. Your module is automatically loaded when a user calls your function. For more information about the module path, see Importing a PowerShell Module and about_PSModulePath

I tested to add the location of my custom modules into $PSModulePath, but the modification was not updated in the downstream tasks. Besides, the suggested steps here didn't seem to work.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.