Deploying Modules to the PowerShell Gallery

So! We've talked about continuous integration and deployment with PSDeploy, the importance of abstraction, and a bit on how and why to write and publish PowerShell modules.

It's time to combine these ingredients with a quick, real-world walk through on automatically publishing your PowerShell modules to the PowerShell Gallery.  If you want a full run-down showing how to deploy PSDeploy with PSDeploy, hit the link; otherwise, we'll pick up the PSStackExchange module where we left off, and drop in some continuous integration and deployment goodness!

Is everything in order?

First things first, what do we already have?

That's about it!  This is all you need to start automatically publishing to the PowerShell Gallery.

Manual steps

There's one manual step to take - we'll use AppVeyor's secure variables feature to encrypt our PowerShell Gallery API key under our AppVeyor account.

Chris Wahl has a quick hit with instructions.  Long story short? Click your AppVeyor account drop down, Encrypt data.  Paste in your API key and Encrypt!  Copy out the resulting encrypted value.

Okay, now what do we do with it?

Drop in the scaffolding!

We're going to download four files and substitute in our encrypted data.  You could use the code below with a few substitutions to add automated deployments to your PowerShell modules:

# Create a folder, clone PSStackExchange, browse to that repo
# Substitute in values for your own module as desired
$Repo = 'C:\sc\PSStackExchange\'
mkdir C:\sc
cd C:\sc
git clone https://github.com/RamblingCookieMonster/PSStackExchange.git
cd $Repo

# We're in the repo! Download 4 scaffolding files:
$wc = New-Object System.Net.WebClient
'https://raw.githubusercontent.com/RamblingCookieMonster/PSDeploy/8b83d7a4e068b08be3293281b3d2c88c9ccd8c16/appveyor.yml',
'https://raw.githubusercontent.com/RamblingCookieMonster/PSDeploy/8b83d7a4e068b08be3293281b3d2c88c9ccd8c16/build.ps1',
'https://raw.githubusercontent.com/RamblingCookieMonster/PSDeploy/8b83d7a4e068b08be3293281b3d2c88c9ccd8c16/psake.ps1',
'https://raw.githubusercontent.com/RamblingCookieMonster/PSDeploy/8b83d7a4e068b08be3293281b3d2c88c9ccd8c16/deploy.psdeploy.ps1' |
    ForEach-Object {
        $File = Join-Path $Repo ($_ -split "/")[-1]
        $wc.DownloadFile( $_, $File )
    }

# Replace my encrypted NuGetApiKey with yours!
$YourKey = 'SomeEncryptedKeyFromAppVeyor'  # <<<<<< Replace this with your encrypted data from AppVeyor <<<<<<
$AppVeyorPath = Join-Path $Repo appveyor.yml
$AppVeyorContent = Get-Content $AppVeyorPath -Raw
Set-Content $AppVeyorPath -Value $AppVeyorContent.replace('secure: oqMFzG8F65K5l572V7VzlZIWU7xnSYDLtSXECJAAURrXe8M2+BAp9vHLT+1h1lR0', "secure: $YourKey")

# Commit your changes, push them to GitHub, and you're good to go!

I made these changes, pushed to GitHub with !Deploy in my commit message, and voila!  AppVeyor ran the build, and PSStackExchange was updated in the gallery!

Wait, what does this all mean?

So! Every time I make a change to PSStackExchange going forward, I have the option to say !Deploy anywhere in my commit message.  When that happens, my changes run through Pester tests in AppVeyor, and are automatically pushed to the PowerShell Gallery in the unlikely event that I didn't make a mistake.

  • Someone submits a bug report and I have a fix to add?  Automatically !Deploy
  • Someone submits a pull request with an awesome new feature?  Automatically !Deploy
  • I discover I've made a terrible mistake and need to re-write something?  Automatically !Deploy
  • I'm literally too lazy to run a single command, with a key I could serialize using the DPAPI?  !Deploy

Okay, to be fair, this pipeline borrows from the PowerShell team and deploys developer builds to AppVeyor regardless of whether you say !Deploy.

More specifically:

  • AppVeyor reads the appveyor.yml, which tells it to run the build.ps1
  • The build.ps1 downloads a few modules, sets some build variables, and runs psake.ps1
  • Psake.ps1 includes our steps to test via Pester, build via BuildHelpers (bump the module version, etc.), and deploy via PSDeploy
  • Deploy.psdeploy.ps1 tells PSDeploy what to deploy, and includes some gates - for example, only deploy the master branch to the PowerShell gallery

That's about it!

Takeaways

Three quick takeaways:

(1) Each of the components in this pipeline, and the pipeline itself are open source:  psake, Pester, PSDeploy, and BuildHelpers.  Feel free to contribute ideas, bug reports, tests, documentation, code, and the like.

(2) It goes without saying, but do consider writing modules, open sourcing them, and publishing them to the PowerShell Gallery - ideally automatically with something like the process we just walked through!

(3) This is a great way to get your feet wet with release pipelines for infrastructure.  You might have different tests, and you might deploy systems and services rather than modules, but ultimately:

  • You're pushing changes to source control
  • You have a build system that watches this, and...
    • Runs a suite of tests
    • Perhaps "builds" some artifacts you need
    • Pushes out your changes.  Perhaps to production

Cheers!

About the Author

Warren Frame

Profile photo of Warren Frame

Systems Engineer with a penchant for PowerShell, science, cooking, information security, family, cookies, and the Oxford comma.

One Comment