This tutorial will demonstrate how to create a simple, single-function module using ModuleForge, with 1 pester test, and deploy via Github workflows.
new-mfProject -ModuleName 'psGetHelloWorld' -description 'Another Hello World module'
source
directory and a module config file moduleForgeConfig.xml
. The source directory shoud have a number of subfoldersadd-mfGithubScaffold
function to add 2 github workflow files and a PR template to the .github
directory of your module folderadd-mfgithubScaffold
feature/hello-world-function
or something similar andfunctions
sub-directory of the source
directory
get-helloWorld.ps1
function get-helloWorld
{
<#
.SYNOPSIS
Return Hello World
.DESCRIPTION
Return Hello World. Allows you to overwrite the default name of world with
.EXAMPLE
get-helloWorld
#### OUTPUT
Returns "Hello World!"
.EXAMPLE
get-helloWorld -name 'James'
#### OUTPUT
Returns "Hello James!"
#>
[CmdletBinding()]
PARAM(
#Name param, specify to override the default of World
[Parameter()]
[string]$name = 'World'
)
begin{
#Return the script name when running verbose, makes it tidier
write-verbose "===========Executing $($MyInvocation.InvocationName)==========="
#Return the sent variables when running debug
Write-Debug "BoundParams: $($MyInvocation.BoundParameters|Out-String)"
}
process{
"Hello $name!"
}
}
functions
sub-directory of the source
directory
get-helloWorld.Tests.ps1
Tests
is in the correct, capital-case format for invoke pester to work as expected. $PSCommandPath.Replace('.Tests.ps1','.ps1')
BeforeAll{
#Load This File
. $PSCommandPath.Replace('.Tests.ps1','.ps1')
}
Describe "get-helloWorld Default Parameters" {
BeforeAll {
$hello = get-helloWorld
}
It 'Should not be null or empty' {
$hello |Should -Not -BeNullOrEmpty
}
It 'Should contain "Hello World!"' {
$hello |Should -Be 'Hello World!'
}
}
Describe "get-helloWorld Custom Name" {
BeforeAll {
$hello = get-helloWorld -name 'James'
}
It 'Should not be null or empty' {
$hello |Should -Not -BeNullOrEmpty
}
It 'Should contain "Hello James!"' {
$hello |Should -Be 'Hello James!'
}
}
invoke-pester '.\source\functions\get-helloworld.Tests.ps1'
feat
commit prefix and a relevant comment
feat: added get-helloWorld function
test
commit prefix
test: added Pester testing for get-helloWorld
X
to help determine your next version, and to make it easier to review later.Merge Pull Request
If you want to explore your pester results in more details before a merge, you can click on
Actions
, find thepesterTest
workflow, and expand theRun pester tests
step from our latest run to view things such as code coverage, or get more details on failures etc
Actions
menuBuild and Release
workflowworkflow_dispatch
event that we can use to version, build and release our code as a PowerShell moduleRun Workflow
option, a menu will appear. Fill out the fields appropriately and then choose run workflow
none
prerelease
code
tab after the workflow completes. You should now see:
latest
badgeDon’t forget to checkout the Main branch on your local working directory before adding any more code.
If you want to manually download and install your new module, you can download the nupkg from the releases page, rename the extension to
.zip
and uncompress to find your module.
In your PowerShell terminal with PSResourceGet ready to go, you can register a new repository. You will only need to register the repository once, as github package feeds are unique to the user or organisation, not the repository.
Microsoft.PowerShell.SecretManagement
module). This is the recommended approachTo register with a credential, see the example code below
### Create a credential object
### Your username will be your github email
### The password will be the github PAT you created
$githubCredential = get-credential
#use the register-psResourceRepository commandlet to register
#This is easier to do with splatting
#Don't forget to swap out the githubaccount with your actual github account
$splat = @{
Name = 'myGithubPackages'
Uri = 'https://nuget.pkg.github.com/{githubaccount}/index.json'
Trusted = $true
}
#Once registered, you can use it in a similar fashion to PSGallery
#Don't forget to specify the -PreRelease flag
Find-PSResource -Name psGetHelloWorld -Prerelease -Repository myGithubPackages -Credential $githubCredential
To register with Microsoft.PowerShell.SecretManagement
, first, create a new secret in your secret vault. The username should be your github email, and the password the PAT you created
### Create a pointer to your secret and vault
### Your username will be your github email
### The password will be the github PAT you created
#You will need to make sure that PSResourceGet module is imported first
$credentialInfo = [Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo]::new('VaultName', 'SecretName')
#use the register-psResourceRepository commandlet to register
#This is easier to do with splatting
#Don't forget to swap out the githubaccount with your actual github account
#
$splat = @{
Name = 'myGithubPackages'
Uri = 'https://nuget.pkg.github.com/{githubaccount}/index.json'
Trusted = $true
CredentialInfo = $credentialInfo
}
#Once registered, you can use it in a similar fashion to PSGallery
#Don't forget to specify the -PreRelease flag
#Because we supplied a CredentialInfo pointer, Find-PSResource will automatically open our vault to retrieve the secret when required
Find-PSResource -Name psGetHelloWorld -Prerelease -Repository myGithubPackages
A note on V3 nuget feeds and PSResourceGet. Wildcard searching is not supplied, you will need to know the exact name of your module for find and install commands to work.
In this tutorial, we created a new repository, added our ModuleForge scaffolding, created a new PowerShell function + test, performed a review and unit test, and released it as a PreRelease into our private Github Packages repository for consumption. We effectively made a CI/CD PowerShell Pipeline using Github Actions + ModuleForge.
The next steps are up to you, you could create a new function and a new prerelease version, or experiment with something a little more advanced.
If you are not a fan of the PR template, feel free to use your own.
If you want to know more about the workflows, feel free to take a look, adjust them, reverse-engineer them, tweak them for your own purposes.