This is a template repository for PowerShell modules and scripts. The template contains concepts such as
- Directory structure
- Modules
- Scripts
- Tests
- CI
- Testing
- Manifest generation
- Publishing
There are two main folders within the src directory
Modulesthat contain the root folder for each module. Within the folder, the manifest.psd1is not present and is excluded from source control. During publishing, the manifest file will be generated by leveraging the information found in the.psm1file. Because the publish engine support auto-increment on the minor version, for this reason the manifest is not source controlled.Scriptsthat contains different script files. Each file must contain a<#PSScriptInfo #>tag that is required by the publishing engine of thePublish-Script. For this reason, auto-increment is not supported as the information is source controlled.
Each module has a Public and Private subfolder that contain the exported and not functions of the module respectively. The publish engine will figure out the public functions and include them in the manifest. Each cmdlet can be paired with a .Tests.ps1 file that contains the tests for Pester.
In a similar fashion, there is the Tests folder that contains the module and script tests. The helper function Get-RandomValue is provided in two forms.
- As an independent script to import with dot sourcing e.g. in Test-M1.Tests.ps1 with
. $PSScriptRoot\..\..\Cmdlets-Helpers\Get-RandomValue.ps1. - As a cmdlet within the
Helpermodule to be used in e.g. Test-M1.Tests.ps1 with& $PSScriptRoot\..\..\Helpers\Import-Helper.ps1instead of. $PSScriptRoot\..\..\Cmdlets-Helpers\Get-RandomValue.ps1.
Pester v5 broke compatibility with the Invoke-Pester cmdlet. It also changed a couple of things in the pipeline and especially how the test scripts are parsed, how tests are detected, how to mock functions and how to use the InModuleScope feature. The Test-M1.Tests.ps1 and Test-M2.Tests.ps1 show how to address all of these concerns.
- Make sure all code is in
BeforeAllorBeforeEachblocks. One sideffect of this is that it is not possible to use variables when declaring the name as part of theDescribeblock. Variable will be empty. - Use
InModuleScopeinside aItblock. - Feed parameters to the
InModuleScopethat are different for eachIttest. - Mock functions.
With version 5, the usage of InModuleScope becomes more complicated and verbose. Based on 1543 and 2009 issues, this is the only way to successfully perform such tests until version 5.3.0.
The CI folder contains scripts to run tests and publish modules. For the purpose of this repository, there is a Mock folder as well that allows publishing to a local file-based PowerShell repository. This mocked concept should not be copied elsewhere and the related functionality should be removed by the mock scripts. When the publish scripts are invoked without a NuGetAPIKey then the flow will execute as normal and if the flow would new to publish a module or a script it will invoke Publish-Module and Publish-Script with the -WhatIf parameter.
The included AppVeyor.yml will execute the publish scripts but without any NuGetAPIKey. When copying the structure you need to follow the instruction for secure variables in AppVeyor's Build Configuration. Then the variable needs to be passed to the publish script. Also, you would probably want to publish only when building the master branch.
version: 1.0.{build}
image: Ubuntu1804
init:
- pwsh: Get-ChildItem ENV:\
install:
- pwsh: # Install-Module -Name Pester -Scope CurrentUser -Force
build: off
test_script:
- pwsh: '& .\CI\Invoke-Test.ps1 -AppVeyor'
for:
-
branches:
only:
- master
environment:
NuGetAPIKey:
secure: <encrypt_value>
deploy_script:
- pwsh: >-
& .\CI\Publish-Module.ps1 -NuGetAPIKey $env:NuGetAPIKey
& .\CI\Publish-Script.ps1 -NuGetAPIKey $env:NuGetAPIKey- Publishing with semantic versioning for AutoIncrement
- Azure DEVOPS yaml file
- VSCode build actions