[HOWTO] Publish PowerShell Module to PowerShellGallery with TeamCity 9.x

Hi I’m Steven Pilatschek, apprentice of the d-fens GmbH. I started my apprenticeship in August 2015. The first year of my apprenticeship I participated a program in a training center. Since August 2016 I’m working at d-fens.

Introduction

As a first task I had to extend the existing build configurations of our PowerShell modules on our TeamCity build server, so that the modules automatically get published to PowerShellGallery. Until now we only published PowerShell modules to NuGet.org. As Microsoft provides another platform for PowerShell modules we decided to switch to this platform in the next few months.

PowerShellGallery Publishing Script

The script will do the following steps and will be integrated into the release job as an additional step.

  1. Change to the directory where the NuGet package was created
  2. Add .zip ending
  3. Unzip NuGet package
  4. Install module
  5. Test module manifest
  6. Load module
  7. Publish module to PowerShellGallery
try 
{
    # Go to the Teamcity directory
    cd %system.PackageDeployOutput%;    

    # Create a zip from the module to upload
    $nupkgFileName = Get-ChildItem -Filter *.nupkg -Name;
    $zipFileName = '{0}.zip' -f $nupkgFileName;
    Rename-Item $nupkgFileName $zipFileName;
    Expand-Archive $zipFileName;

    # Change directory and put the directory to the stack
    Push-Location $nupkgFileName;

    # Install module to upload
    .\Install.ps1;

    # Put the directory into the stack
    Push-Location tools;
    $pathToPsd1 = (Get-ChildItem *.psd1 -File | Select -First 1).FullName;
    $psd1 = Test-ModuleManifest $pathToPsd1;

    # The final step, upload it on Powershellgallery.com DON'T forget the API key
    $module = Get-Module $psd1.Name -ListAvailable;
    $module | Publish-Module -NuGetApiKey %NuGetApiKey% -Confirm:$false;
} 
catch 
{
    # If something fails, PowerShell will get an error and writes the exception in the build log
    Write-Host "##teamcity[buildStatus status='FAILURE' text='Publish module to PowerShellGallery.com FAILED']";
    $teamcityErrorMessage = $_.Exception.Message;
    Write-Host $teamcityErrorMessage;
}
finally
{
    if ($module)
    {
        # Uninstall/remove module
        $pathToDelete = "{0}{1}" -f $module.Path, "\..\..\..";
        cd $pathToDelete;
        Remove-Item $module.Name -Force -Recurse;
    }
}

IMPORTANT: Script requires PowerShell version 5.0.

Integrate the Script for publishing

Now I show you how to integrate this script into the existing release job. Our existing release jobs contain the following steps

  1. Install NuGet packages
  2. Create NuGet package
  3. Publish NuGet package to NuGet.org

First of all make sure your PowerShell version on the build server is at 5.0, as the script uses some functions that are not available in lower versions.
We are using some Environment variables (build parameters) in the script (like the %NuGetApiKey%). These parameters have to be defined to make the script work. You can learn how to define such parameters by yourself here.

  1. Go to the corresponding release configuration
  2. Select “Build Steps”
    TeamCity-Publish-PowerShellGallery-1
  3. Add a new build step
    TeamCity-Publish-PowerShellGallery-2
  4. As Runner type select PowerShell
  5. On the script dropdown, select Source code
    TeamCity-Publish-PowerShellGallery-3
  6. Copy the script above to the text area
  7. Set Script execution Mode to Execute -ps1 from external file
  8. Save the new build step

Now you’re done!

Challenges

We had some problems when loading module directly from unzipped NuGet package as PowerShell was not able to locate the module under one of the default module path. We decided to first install the module on the build server, load the module from the default modules directory (Get-Module $moduleName -ListAvailable) so the upload could work.

If you want to use TeamCity service messages like setting the build status, you need to write the service message with Write Host to the build log. The example in our case:

Write-Host "##teamcity[buildStatus status='FAILURE' text='Publish module to PowerShellGallery.com FAILED']";

Thank you for reading this Blogpost!

icon_TeamCity
The TeamCity Free Open Source License was generously provided by JetBrains

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: