diff --git a/PSModuleDevelopment/PSModuleDevelopment.psd1 b/PSModuleDevelopment/PSModuleDevelopment.psd1
index f78ff2a..d5096d8 100644
--- a/PSModuleDevelopment/PSModuleDevelopment.psd1
+++ b/PSModuleDevelopment/PSModuleDevelopment.psd1
@@ -4,9 +4,10 @@
RootModule = 'PSModuleDevelopment.psm1'
# Version number of this module.
- ModuleVersion = '2.2.10.134'
- # ID used to uniquely identify this module
+ ModuleVersion = '2.2.11.138'
+
+ # ID used to uniquely identify this module
GUID = '37dd5fce-e7b5-4d57-ac37-832055ce49d6'
# Author of this module
@@ -156,11 +157,4 @@
} # End of PSData hashtable
} # End of PrivateData hashtable
-}
-
-
-
-
-
-
-
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.dll b/PSModuleDevelopment/bin/PSModuleDevelopment.dll
index 3a051c1..57ef0fa 100644
Binary files a/PSModuleDevelopment/bin/PSModuleDevelopment.dll and b/PSModuleDevelopment/bin/PSModuleDevelopment.dll differ
diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.pdb b/PSModuleDevelopment/bin/PSModuleDevelopment.pdb
index 49f6b65..c0a219a 100644
Binary files a/PSModuleDevelopment/bin/PSModuleDevelopment.pdb and b/PSModuleDevelopment/bin/PSModuleDevelopment.pdb differ
diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.xml b/PSModuleDevelopment/bin/PSModuleDevelopment.xml
index 40be847..8fb47fb 100644
--- a/PSModuleDevelopment/bin/PSModuleDevelopment.xml
+++ b/PSModuleDevelopment/bin/PSModuleDevelopment.xml
@@ -682,6 +682,43 @@
Items under the current item.
+
+
+ The result object of a template invokation item.
+ A project template will generate one such object per file/folder
+
+
+
+
+ Name of the file or folder
+
+
+
+
+ Path the file or folder should be written to
+
+
+
+
+ The full, resolved path of the item
+
+
+
+
+ Any content to write (only viable for files)
+
+
+
+
+ Whether the item to create is a folder or a file
+
+
+
+
+ Whether the file is a text-file.
+ If false, it will be written as a binary file instead.
+
+
Is the template a single file or a project?
diff --git a/PSModuleDevelopment/changelog.md b/PSModuleDevelopment/changelog.md
index 4aa9fb1..b17262c 100644
--- a/PSModuleDevelopment/changelog.md
+++ b/PSModuleDevelopment/changelog.md
@@ -1,5 +1,12 @@
# Changelog
+## 2.2.11.138 (2022-04-19)
+
++ New: Template MiniModule - a scaffold for a minimal dependencies module
++ Upd: Invoke-PSMDTemplate - added parameter `-GenerateObjects` to return objects representing what would have been created as file, rather than actually creating files / folders. (@Callidus2000; #167)
++ Upd: Restart-PSMDShell (rss) - added support for Windows Terminal
++ Upd: Template AzureFunction - added Azure.Function.Tools as a dependency, dropped the automatic Az dependency (still available though)
+
## 2.2.10.134 (2022-03-17)
+ New: Test-PSMDClmCompatibility - Tests, whether the targeted file would have trouble executing under Constrained Language Mode.
@@ -19,214 +26,239 @@
## 2.2.10.123 (2021-07-21)
-- Fix: Template PSFProject - fixed string test modulename
-- Fix: Template PSFModule - fixed string test modulename
-- Fix: Template PSFTest - fixed string test modulename
++ Fix: Template PSFProject+ Fixed string test modulename
++ Fix: Template PSFModule+ Fixed string test modulename
++ Fix: Template PSFTest+ Fixed string test modulename
## 2.2.10.120 (2021-07-20)
-- New: Build Component - define build workflows based on pre-defined & extensible action code
-- Upd: Template AzureFunction - new layout with better build automation
-- Upd: Template AzureFunctionRest - new layout to integrate into new AzureFunction template
-- Upd: Template PSFProject - added Github Actions integration
-- Upd: Aliases - removed "AllScope" option
-- Fix: Template PSFTest - fixed PSScriptAnalyzer test path detection
-- Fix: Template PSFTest - fixed string LegalSurplus exception being ignored
-- Fix: Template PSFModule - fixed PSScriptAnalyzer test path detection
-- Fix: Template PSFModule - fixed string LegalSurplus exception being ignored
-- Fix: Template PSFProject - fixed PSScriptAnalyzer test path detection
-- Fix: Template PSFProject - fixed string LegalSurplus exception being ignored
-- Fix: TemplateStore - default path iss invalid on MAC (#136)
-- Fix: Invoke-PSMDTemplate - unreliable string replacement through -replace operator (#113)
-- Fix: Publish-PSMDScriptFile - insufficient exclude paths (#138; @Callidus2000)
++ New: Build Component - define build workflows based on pre-defined & extensible action code
++ Upd: Template AzureFunction+ New layout with better build automation
++ Upd: Template AzureFunctionRest+ New layout to integrate into new AzureFunction template
++ Upd: Template PSFProject - added Github Actions integration
++ Upd: Aliases - removed "AllScope" option
++ Fix: Template PSFTest+ Fixed PSScriptAnalyzer test path detection
++ Fix: Template PSFTest+ Fixed string LegalSurplus exception being ignored
++ Fix: Template PSFModule+ Fixed PSScriptAnalyzer test path detection
++ Fix: Template PSFModule+ Fixed string LegalSurplus exception being ignored
++ Fix: Template PSFProject+ Fixed PSScriptAnalyzer test path detection
++ Fix: Template PSFProject+ Fixed string LegalSurplus exception being ignored
++ Fix: TemplateStore - default path iss invalid on MAC (#136)
++ Fix: Invoke-PSMDTemplate - unreliable string replacement through -replace operator (#113)
++ Fix: Publish-PSMDScriptFile - insufficient exclude paths (#138; @Callidus2000)
## 2.2.9.106 (September 10th, 2020)
-- New: Convert-PSMDMessage - Converts a file's use of PSFramework messages to strings.
-- Upd: Export-PSMDString - Adding support for Test-PSFShouldProcess.
-- Fix: Export-PSMDString - Failed with splatting detection
++ New: Convert-PSMDMessage - Converts a file's use of PSFramework messages to strings.
++ Upd: Export-PSMDString - Adding support for Test-PSFShouldProcess.
++ Fix: Export-PSMDString - Failed with splatting detection
## 2.2.8.104 (July 26th, 2020)
-- Fix: Various bugs in the new functions
++ Fix: Various bugs in the new functions
## 2.2.8.103 (July 24th, 2020)
-- New: Publish-PSMDScriptFile - Packages a script with all dependencies and "publishes" it as a zip package.
-- New: Get-PSMDFileCommand - Parses a scriptfile and returns the contained/used commands.
-- New: Set-PSMDStagingRepository - Define the repository to use for deploying modules along with scripts.
-- New: Publish-PSMDStagedModule - Publish a module to your staging repository.
-- Fix: Export-PSMDString - Random failure to execute (thanks @AndiBellstedt !)
++ New: Publish-PSMDScriptFile - Packages a script with all dependencies and "publishes" it as a zip package.
++ New: Get-PSMDFileCommand - Parses a scriptfile and returns the contained/used commands.
++ New: Set-PSMDStagingRepository - Define the repository to use for deploying modules along with scripts.
++ New: Publish-PSMDStagedModule - Publish a module to your staging repository.
++ Fix: Export-PSMDString - Random failure to execute (thanks @AndiBellstedt !)
## 2.2.7.98 (May 30th, 2020)
-- Upd: Template PSFTest - Pester v5 compatibility
-- Upd: Template PSFModule - Pester v5 compatibility
-- Upd: Template PSFProject - Pester v5 compatibility
-- Upd: Template PSFProject - Simplified module import workflow
-- Upd: Template PSFProject - Improved build process cross-agent convenience
-- Upd: Template PSFProject - Prerequisites task automatically detects module dependencies
-- Upd: Template PSFProject - Prerequisites task can be configured to work with any registered repository
-- Upd: Export-PSMDString - Now also detects splatted localization strings (thanks @StevePlp ; #117)
++ Upd: Template PSFTest - Pester v5 compatibility
++ Upd: Template PSFModule - Pester v5 compatibility
++ Upd: Template PSFProject - Pester v5 compatibility
++ Upd: Template PSFProject - Simplified module import workflow
++ Upd: Template PSFProject - Improved build process cross-agent convenience
++ Upd: Template PSFProject - Prerequisites task automatically detects module dependencies
++ Upd: Template PSFProject - Prerequisites task can be configured to work with any registered repository
++ Upd: Export-PSMDString - Now also detects splatted localization strings (thanks @StevePlp ; #117)
## 2.2.7.90 (September 1st, 2019)
- - New: Export-PSMDString - Parses strings from modules using the PSFramework localization feature.
- - Upd: Measure-PSMDCommand - Renamed from Measure-PSMDCommandEx, performance upgrades, adding option for comparing multiple test sets.
- - Upd: Refactored and updated the ModuleDebug component
- - Upd: Renamed Get-PSMDHelpEx to Get-PSMDHelp
- - Upd: Template PSFProject - Adding `-IncludAZ` switch parameter to `vsts-packageFunction.ps1`, making the template include the AZ module as managed dependency.
- - Upd: Template PSFProject - yaml file for AzDev PR validation pipeline
- - Upd: Refactored module structure to comply with current Fred Reference Architecture
- - Upd: Template PSFTests - Added localization string tests
- - Upd: Remove-PSMDTemplate - Refactored and updated messaging / ShouldProcess implementation
- - Upd: Find-PSMDFileContent - Updated extension filtering to be configurable and include .cs files by default.
- - Upd: Get-PSMDArgumentCompleter - Refactoring and minor performance improvement
- - Upd: Restart-PSMDShell - Will restart same application as current process, enabling it to restart on core versions
- - Fix: Template PSFProject - Publish Folder created during build is created using `-Force`
- - Fix: Template PSFProject - Cleaning up Azure Function conversion
- - Fix: Template PSFTests - Encoding test no longer fails on core (#104)
- - Fix: Template PSFTests - Referenced DLLs from GAC will fail as path cannot be found (#100)
- - Fix: Template Module - RootModule | 3-element version | Module Import from UNC path
- - Fix: Template-System - Bad default template store path on linux or mac. (#106)
+
++ New: Export-PSMDString - Parses strings from modules using the PSFramework localization feature.
++ Upd: Measure-PSMDCommand - Renamed from Measure-PSMDCommandEx, performance upgrades, adding option for comparing multiple test sets.
++ Upd: Refactored and updated the ModuleDebug component
++ Upd: Renamed Get-PSMDHelpEx to Get-PSMDHelp
++ Upd: Template PSFProject - Adding `-IncludAZ` switch parameter to `vsts-packageFunction.ps1`, making the template include the AZ module as managed dependency.
++ Upd: Template PSFProject - yaml file for AzDev PR validation pipeline
++ Upd: Refactored module structure to comply with current Fred Reference Architecture
++ Upd: Template PSFTests - Added localization string tests
++ Upd: Remove-PSMDTemplate - Refactored and updated messaging / ShouldProcess implementation
++ Upd: Find-PSMDFileContent+ Updated extension filtering to be configurable and include .cs files by default.
++ Upd: Get-PSMDArgumentCompleter - Refactoring and minor performance improvement
++ Upd: Restart-PSMDShell - Will restart same application as current process, enabling it to restart on core versions
++ Fix: Template PSFProject - Publish Folder created during build is created using `-Force`
++ Fix: Template PSFProject - Cleaning up Azure Function conversion
++ Fix: Template PSFTests - Encoding test no longer fails on core (#104)
++ Fix: Template PSFTests - Referenced DLLs from GAC will fail as path cannot be found (#100)
++ Fix: Template Module - RootModule | 3-element version | Module Import from UNC path
++ Fix: Template-System - Bad default template store path on linux or mac. (#106)
## 2.2.6.72 (May 27th, 2019)
- - New: Template AzureFunction - Creates a basic azure function scaffold
- - New: Template AzureFunctionTimer - Creates a timer triggered Azure Function
- - Upd: Template AzureFunctionRest - Redesigned to only spawn a function rest endpoint to insert into the base AzureFunction template.
- - Upd: Template PSFProject - Improved Azure Functions creation experience, added client module support.
+
++ New: Template AzureFunction - Creates a basic azure function scaffold
++ New: Template AzureFunctionTimer - Creates a timer triggered Azure Function
++ Upd: Template AzureFunctionRest - Redesigned to only spawn a function rest endpoint to insert into the base AzureFunction template.
++ Upd: Template PSFProject - Improved Azure Functions creation experience, added client module support.
## 2.2.6.68 (May 3rd, 2019)
- - Upd: Template PSFProject - Improved Azure Functions creation experience
+
++ Upd: Template PSFProject - Improved Azure Functions creation experience
## 2.2.6.67 (May 2nd, 2019)
- - Upd: Invoke-PSMDTemplate adding tab completion
- - Fix: Invoke-PSMDTemplate fails to create templates
+
++ Upd: Invoke-PSMDTemplate adding tab completion
++ Fix: Invoke-PSMDTemplate fails to create templates
## 2.2.6.65 (May 2nd, 2019)
- - New: Template: AzureFunctionRest - creates an azure function designed for rest API trigger.
- - Upd: Template: PSFProject added Azure Functions Project CI/CD integration.
- - Upd: Invoke-PSMDTemplate supports `-Encoding` parameter, defaulting to utf8 with BOM.
+
++ New: Template: AzureFunctionRest - creates an azure function designed for rest API trigger.
++ Upd: Template: PSFProject added Azure Functions Project CI/CD integration.
++ Upd: Invoke-PSMDTemplate supports `-Encoding` parameter, defaulting to utf8 with BOM.
## 2.2.6.62 (April 30th, 2019)
- - New: Get-PSMDArgumentCompleter - Lists registered argument completers on PS5+
- - New: Template: PSFLoggingProvider - Creates a custom logfile logging provider for module specific logging.
- - Upd: Template: PSFTest - Adding test against module tags with whitespace
- - Upd: Get-PSMDConstructor - Added `-NonPublic` parameter to show hidden constructors.
- - Upd: Template: PSFModule - Improved import speed.
- - Upd: Template: PSFProject - Add parameter `-LocalRepo`
- - Upd: Template: PSFProject - Add parameter `-AutoVersion`
- - Fix: New-PSMDModuleNugetPackage - Resolving input path.
- - Fix: New-PSMDModuleNugetPackage - Reregistering temp export repository if accidentally not cleaned up.
- - Fix: Template: PSFModule - Fixed format xml closing tag
- - Fix: Template: PSFModule - Fixed import from network share.
-
+
++ New: Get-PSMDArgumentCompleter - Lists registered argument completers on PS5+
++ New: Template: PSFLoggingProvider - Creates a custom logfile logging provider for module specific logging.
++ Upd: Template: PSFTest - Adding test against module tags with whitespace
++ Upd: Get-PSMDConstructor - Added `-NonPublic` parameter to show hidden constructors.
++ Upd: Template: PSFModule - Improved import speed.
++ Upd: Template: PSFProject - Add parameter `-LocalRepo`
++ Upd: Template: PSFProject - Add parameter `-AutoVersion`
++ Fix: New-PSMDModuleNugetPackage - Resolving input path.
++ Fix: New-PSMDModuleNugetPackage - Reregistering temp export repository if accidentally not cleaned up.
++ Fix: Template: PSFModule+ Fixed format xml closing tag
++ Fix: Template: PSFModule+ Fixed import from network share.
+
## 2.2.6.51 (January 29th, 2019)
- - New: Format-PSMDParameter - updates legacy parameter notation
- - New: Measure-PSMDLinesOfCode - Measures the lines of code in a scriptfile.
- - New: Search-PSMDPropertyValue - search objects for values in properties
- - Upd: Template PSFTest - adding WMI commands to list of forbidden commands
- - Upd: Template PSFModule - adding changelog
- - Upd: Template PSFModule - adding strings for localization
- - Upd: Template PSFModule - adding scriptblocks
- - Upd: Template PSFProject - updated build txt files to include new module content
- - Fix: Template PSMTest - replacing all -Filter calls on Get-ChildItem
- - Fix: New-PSMDTemplate records binary files as text files
+
++ New: Format-PSMDParameter+ Updates legacy parameter notation
++ New: Measure-PSMDLinesOfCode - Measures the lines of code in a scriptfile.
++ New: Search-PSMDPropertyValue - search objects for values in properties
++ Upd: Template PSFTest - adding WMI commands to list of forbidden commands
++ Upd: Template PSFModule - adding changelog
++ Upd: Template PSFModule - adding strings for localization
++ Upd: Template PSFModule - adding scriptblocks
++ Upd: Template PSFProject+ Updated build txt files to include new module content
++ Fix: Template PSMTest - replacing all -Filter calls on Get-ChildItem
++ Fix: New-PSMDTemplate records binary files as text files
## 2.2.5.41 (December 18th, 2018)
- - Fix: Get-PSMDMember - dropping the unintentional bool return
+
++ Fix: Get-PSMDMember - dropping the unintentional bool return
## 2.2.5.40 (December 17th, 2018)
- - New: Command Show-PSMDSyntax, used to show the parameter syntax with proper highlighting
- - New: Command Get-PSMDMember, used to show the members in a more organic and useful way
- - Fix: Template PSFProject build step was broken
+
++ New: Command Show-PSMDSyntax, used to show the parameter syntax with proper highlighting
++ New: Command Get-PSMDMember, used to show the members in a more organic and useful way
++ Fix: Template PSFProject build step was broken
## 2.2.5.37 ( October 20th, 2018)
- - Upd: Set-PSMDModulePath - add `-Module` parameter to persist the setting
- - Upd: Set-PSMDModulePath - add `-Register` parameter for integrated persistence
- - Upd: Set-PSMDEncoding - use `PSFEncoding` parameter class & tabcompletion
- - Upd: Template PSFProject - build directly into psm1
- - Upd: Template PSFProject, PSFModule - automatically read version in psm1 from psd1, rather than requiring explicit maintenance.
- - Fix: Template PSFTest - use category exclusions
+
++ Upd: Set-PSMDModulePath - add `-Module` parameter to persist the setting
++ Upd: Set-PSMDModulePath - add `-Register` parameter for integrated persistence
++ Upd: Set-PSMDEncoding - use `PSFEncoding` parameter class & tabcompletion
++ Upd: Template PSFProject - build directly into psm1
++ Upd: Template PSFProject, PSFModule - automatically read version in psm1 from psd1, rather than requiring explicit maintenance.
++ Fix: Template PSFTest - use category exclusions
## 2.2.5.31 (September 29th, 2018)
- - Fix: Template PSFProject dependencies installed correctly
-
+
++ Fix: Template PSFProject dependencies installed correctly
+
## 2.2.5.30 (September 12th, 2018)
- - Upd: Template integrated NUnit Test Reporting
- - Upd: Template support for compiled module files
+
++ Upd: Template integrated NUnit Test Reporting
++ Upd: Template support for compiled module files
## 2.2.5.28 (September 08th, 2018)
- - Fix: Template CommandTest would throw an exception due to missing quotes on a string index
+
++ Fix: Template CommandTest would throw an exception due to missing quotes on a string index
## 2.2.5.27 (September 08th, 2018)
- - Fix: Fixes in the build task
+
++ Fix: Fixes in the build task
## 2.2.5.26 (September 08th, 2018)
- - New: Command Read-PSMDScript (Alias: parse)
- - New: Command Set-PSMDEncoding
- - New: Template PSFTests - Default module tests
- - New: Template CommandTest - A tempalte that generate a test from an already existing command.
- - Upd: Template PSFModule - some fixes
- - Upd: Template PSFProject - some fixes and improvements to the installer
- - Fix: Template function - encoding error
- - Fix: New-PSMDTemplate - now properly selects scriptblocks across multiple lines
+
++ New: Command Read-PSMDScript (Alias: parse)
++ New: Command Set-PSMDEncoding
++ New: Template PSFTests - Default module tests
++ New: Template CommandTest - A tempalte that generate a test from an already existing command.
++ Upd: Template PSFModule - some fixes
++ Upd: Template PSFProject - some fixes and improvements to the installer
++ Fix: Template function - encoding error
++ Fix: New-PSMDTemplate - now properly selects scriptblocks across multiple lines
## 2.2.4.18 (May 04rd, 2018)
- - Upd: New-PSMDFormatTableDefinition - Update to add parameters `-IncludePropertyAttribute` and `-ExcludePropertyAttribute`
-
+
++ Upd: New-PSMDFormatTableDefinition+ Update to add parameters `-IncludePropertyAttribute` and `-ExcludePropertyAttribute`
+
## 2.2.3.17 (May 04rd, 2018)
- - Upd: New-PSMDFormatTableDefinition - Major redesign, extensive additional functionality (#29)
- - Upd: Find-PSMDType - add `-Attribute` parameter to filter by class attributes (#27)
- - Fix: Find-PSMDType - suppress error that gets thrown on empty assemblies.
- - Fix: New-PSMDFormatTableDefinition - Broken closing `` tag (#28)
+
++ Upd: New-PSMDFormatTableDefinition - Major redesign, extensive additional functionality (#29)
++ Upd: Find-PSMDType - add `-Attribute` parameter to filter by class attributes (#27)
++ Fix: Find-PSMDType - suppress error that gets thrown on empty assemblies.
++ Fix: New-PSMDFormatTableDefinition - Broken closing `` tag (#28)
## 2.2.1.12 (March 08th, 2018)
- - Added out-of-the box templates
- - fix: Verious bugfixes around the template system
+
++ Added out-of-the box templates
++ Fix: Verious bugfixes around the template system
## 2.2.1.11 (March 06th, 2018)
- - new: Alias imt --> Invoke-PSMDTemplate
- - Upd: Added TabCompletion to *-PSMDTemplate commands
+
++ New: Alias imt --> Invoke-PSMDTemplate
++ Upd: Added TabCompletion to *-PSMDTemplate commands
## 2.2.0.10 (March 06th, 2018)
- - new: Command New-PSMDTemplate
- - new: Command Get-PSMDTemplate
- - new: Command Invoke-PSMDTemplate
- - new: Command Remove-PSMDTemplate
+
++ New: Command New-PSMDTemplate
++ New: Command Get-PSMDTemplate
++ New: Command Invoke-PSMDTemplate
++ New: Command Remove-PSMDTemplate
## 2.1.1.3 (February 06th, 2018)
- - new: Command New-PSMDModuleNugetPackage - A command that takes a module and writes it to a Nuget package.
- - Upd: Increased PSFramework required version to 0.9.9.19
+
++ New: Command New-PSMDModuleNugetPackage - A command that takes a module and writes it to a Nuget package.
++ Upd: Increased PSFramework required version to 0.9.9.19
## 2.1.0.1 (January 24th, 2018)
- - new: Included suite of tests, in order to provide a more reliable user experience.
- - new: Command New-PSMDDotNetProject - A wrapper around dotnet.exe
+
++ New: Included suite of tests, in order to provide a more reliable user experience.
++ New: Command New-PSMDDotNetProject - A wrapper around dotnet.exe
## 2.0.0.0 (December 18th, 2017)
- - Breaking change: Renamed all commands to include the PSMD prefix
- - New function: Find-PSMDFileContent (alias: find), to swiftly search in your current project
- - New function: New-PSMDHeader, to create headers for documentation
- - New function: Set-PSMDModulePath, to define the project currently being worked on
- - Suite of new functions that refactor a project:
-```
++ Breaking change: Renamed all commands to include the PSMD prefix
++ New function: Find-PSMDFileContent (alias: find), to swiftly search in your current project
++ New function: New-PSMDHeader, to create headers for documentation
++ New function: Set-PSMDModulePath, to define the project currently being worked on
++ Suite of new functions that refactor a project:
+
+```text
Rename-PSMDParameter: Renames a parameter, then updates the function's internal use, then updates the parameter usage across the entire module.
Set-PSMDCmdletBinding: Inserts a CmdletBinding-Attribute into all functions that need one
Set-PSMDParameterHelp: Globally updates parameter help for all commands that share a parameter across the project
Split-PSMDScriptFile: Exports all functions in a file and creates new files, one per function, named after the function
```
- - New function: New-PSMDFormatTableDefinition, creates format xml for input types that will present it by default as a table
- - New function: Expand-PSMDTypeName, returns a list of all type-names an object has (by default, the entire inheritance chain)
- - New function: Find-PSMDType, search currently imported assemblies for types
- - New function: Get-PSMDAssembly, return the currently imported assemblies
- - New function: Get-PSMDConstructor, return the constructor definitions for a type or the type of an input object
++ New function: New-PSMDFormatTableDefinition, creates format xml for input types that will present it by default as a table
++ New function: Expand-PSMDTypeName, returns a list of all type-names an object has (by default, the entire inheritance chain)
++ New function: Find-PSMDType, search currently imported assemblies for types
++ New function: Get-PSMDAssembly, return the currently imported assemblies
++ New function: Get-PSMDConstructor, return the constructor definitions for a type or the type of an input object
-## 1.3.0.0 (October 19th, 2016):
- - New function: Measure-CommandEx
- - Renamed function: Get-ExHelp --> Get-HelpEx
- - New Alias: Get-ExHelp --> Get-HelpEx
- - New Alias: hex --> Get-HelpEx
-
-## 1.2.0.0 (August 15th, 2016):
- - New function: Get-ExHelp
+## 1.3.0.0 (October 19th, 2016)
+
++ New function: Measure-CommandEx
++ Renamed function: Get-ExHelp --> Get-HelpEx
++ New Alias: Get-ExHelp --> Get-HelpEx
++ New Alias: hex --> Get-HelpEx
+
+## 1.2.0.0 (August 15th, 2016)
+
++ New function: Get-ExHelp
diff --git a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
index 4652ffe..a33d922 100644
--- a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
+++ b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
@@ -1,5 +1,5 @@
function Invoke-PSMDTemplate {
-<#
+ <#
.SYNOPSIS
Creates a project/file from a template.
@@ -49,6 +49,10 @@
By default, all parameters will be replaced during invocation.
In Raw mode, this is skipped, reproducing mostly the original template input (dynamic scriptblocks will now be named scriptblocks)).
+ .PARAMETER GenerateObjects
+ By default, Invoke-PSMDTemplate generates files.
+ In GenerateObjects mode, no file but objects are created.
+
.PARAMETER Force
If the target path the template should be written to (filename or folder name within $OutPath), then overwrite it.
By default, this function will fail if an overwrite is required.
@@ -78,7 +82,8 @@
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSPossibleIncorrectUsageOfAssignmentOperator", "")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
- [Alias('imt')]
+ [OutputType([PSModuleDevelopment.Template.TemplateResult])]
+ [Alias('imt')]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'NameStore')]
@@ -119,6 +124,9 @@
[switch]
$Raw,
+ [switch]
+ $GenerateObjects,
+
[switch]
$Force,
@@ -175,6 +183,9 @@
[bool]
$Raw,
+ [switch]
+ $GenerateObjects,
+
[bool]
$Silent
)
@@ -212,13 +223,11 @@
}
}
#endregion Scripts
-
- switch ($templateData.Type.ToString()) {
+ $createdTemplateItems = switch ($templateData.Type.ToString()) {
#region File
- "File"
- {
+ "File" {
foreach ($child in $templateData.Children) {
- Write-TemplateItem -Item $child -Path $OutPath -Encoding $Encoding -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
+ New-TemplateItem -Item $child -Path $OutPath -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
}
if ($Raw -and $templateData.Scripts.Values) {
$templateData.Scripts.Values | Export-Clixml -Path (Join-Path $OutPath "_PSMD_ParameterScripts.xml")
@@ -227,8 +236,7 @@
#endregion File
#region Project
- "Project"
- {
+ "Project" {
#region Resolve output folder
if (-not $NoFolder) {
if ($Parameters["Name"]) {
@@ -247,7 +255,7 @@
#endregion Resolve output folder
foreach ($child in $templateData.Children) {
- Write-TemplateItem -Item $child -Path $newFolder.FullName -Encoding $Encoding -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
+ New-TemplateItem -Item $child -Path $newFolder.FullName -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
}
#region Write Config File (Raw)
@@ -278,17 +286,26 @@
$optionsTemplate = $optionsTemplate -replace "þþþPLACEHOLDER-$($guid)þþþ", ""
}
- $configFile = Join-Path $newFolder.FullName "PSMDTemplate.ps1"
- Set-Content -Path $configFile -Value $optionsTemplate -Encoding ([PSFEncoding]'utf-8').Encoding
+ [PSModuleDevelopment.Template.TemplateResult]@{
+ Name = "PSMDTemplate.ps1"
+ Path = $newFolder.FullName
+ FullPath = (Join-Path $newFolder.FullName "PSMDTemplate.ps1")
+ Content = $optionsTemplate
+ }
}
#endregion Write Config File (Raw)
}
#endregion Project
}
+ If ($GenerateObjects) {
+ return $createdTemplateItems
+ }
+ Write-TemplateResult -TemplateResult $createdTemplateItems -Encoding $Encoding
}
- function Write-TemplateItem {
+ function New-TemplateItem {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
+ [OutputType([PSModuleDevelopment.Template.TemplateResult])]
[CmdletBinding()]
param (
[PSModuleDevelopment.Template.TemplateItemBase]
@@ -297,9 +314,6 @@
[string]
$Path,
- [PSFEncoding]
- $Encoding,
-
[hashtable]
$ParameterFlat,
@@ -309,8 +323,7 @@
[bool]
$Raw
)
-
- Write-PSFMessage -Level Verbose -Message "Creating file: $($Item.Name) ($($Item.RelativePath))" -FunctionName Invoke-PSMDTemplate -ModuleName PSModuleDevelopment -Tag 'create', 'template'
+ Write-PSFMessage -Level Verbose -Message "Creating Template-Item: $($Item.Name) ($($Item.RelativePath))" -FunctionName Invoke-PSMDTemplate -ModuleName PSModuleDevelopment -Tag 'create', 'template'
$identifier = $Item.Identifier
$isFile = $Item.GetType().Name -eq 'TemplateItemFile'
@@ -320,7 +333,7 @@
$fileName = $Item.Name
if (-not $Raw) {
foreach ($param in $Item.FileSystemParameterFlat) {
- $fileName = [PSModuleDevelopment.Utility.UtilityHost]::Replace($fileName,"$($identifier)$($param)$($identifier)", $ParameterFlat[$param], $false)
+ $fileName = [PSModuleDevelopment.Utility.UtilityHost]::Replace($fileName, "$($identifier)$($param)$($identifier)", $ParameterFlat[$param], $false)
}
foreach ($param in $Item.FileSystemParameterScript) {
$fileName = [PSModuleDevelopment.Utility.UtilityHost]::Replace($fileName, "$($identifier)$($param)$($identifier)", $ParameterScript[$param], $false)
@@ -338,11 +351,22 @@
$text = [PSModuleDevelopment.Utility.UtilityHost]::Replace($text, "$($identifier)!$($param)!$($identifier)", $ParameterScript[$param], $false)
}
}
- [System.IO.File]::WriteAllText($destPath, $text, $Encoding)
+ return [PSModuleDevelopment.Template.TemplateResult]@{
+ Name = $fileName
+ Path = $Path
+ FullPath = $destPath
+ Content = $text
+ }
}
else {
$bytes = [System.Convert]::FromBase64String($Item.Value)
- [System.IO.File]::WriteAllBytes($destPath, $bytes)
+ return [PSModuleDevelopment.Template.TemplateResult]@{
+ Name = $fileName
+ Path = $Path
+ FullPath = $destPath
+ Content = $bytes
+ IsText = $false
+ }
}
}
#endregion File
@@ -358,26 +382,71 @@
$folderName = $folderName -replace "$($identifier)!$([regex]::Escape($param))!$($identifier)", $ParameterScript[$param]
}
}
- $folder = New-Item -Path $Path -Name $folderName -ItemType Directory
+ $folder = Join-Path -Path $Path -ChildPath $folderName
+
+ # Return a folder object to make sure empty folders are not excluded
+ [PSModuleDevelopment.Template.TemplateResult]@{
+ Name = $folderName
+ Path = $Path
+ FullPath = $folder
+ IsFolder = $true
+ IsText = $false
+ }
foreach ($child in $Item.Children) {
- Write-TemplateItem -Item $child -Path $folder.FullName -Encoding $Encoding -ParameterFlat $ParameterFlat -ParameterScript $ParameterScript -Raw $Raw
+ New-TemplateItem -Item $child -Path $folder -ParameterFlat $ParameterFlat -ParameterScript $ParameterScript -Raw $Raw
}
}
#endregion Folder
}
+
+ function Write-TemplateResult {
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
+ [CmdletBinding()]
+ param (
+ [PSModuleDevelopment.Template.TemplateResult[]]
+ $TemplateResult,
+
+ [PSFEncoding]
+ $Encoding
+ )
+ $msgParam = @{ Level = 'Verbose'; FunctionName = 'Invoke-PSMDTemplate' }
+ foreach ($item in $TemplateResult | Sort-Object { $_.FullPath.Length }) {
+ Write-PSFMessage @msgParam -Message "Creating file: $($item.FullPath)" -FunctionName Invoke-PSMDTemplate -ModuleName PSModuleDevelopment -Tag 'create', 'template'
+ if (-not (Test-Path $item.Path)) {
+ Write-PSFMessage -Level Verbose -Message "Creating Folder $($item.Path)"
+ $null = New-Item -Path $item.Path -ItemType Directory
+ }
+ if ($item.IsFolder) {
+ if (-not (Test-Path $item.FullPath)) {
+ Write-PSFMessage @msgParam -Message "Creating Folder $($item.FullPath)"
+ $null = New-Item -Path $item.FullPath -ItemType Directory
+ }
+ continue
+ }
+ if ($item.IsText) {
+ Write-PSFMessage @msgParam -Message "Creating as a Text-File"
+ [System.IO.File]::WriteAllText($item.FullPath, $item.Content, $Encoding)
+ }
+ else {
+ Write-PSFMessage @msgParam -Message "Creating as a Binary-File"
+ [System.IO.File]::WriteAllBytes($item.FullPath, $item.Content)
+ }
+ }
+ }
#endregion Helper function
}
process {
if (Test-PSFFunctionInterrupt) { return }
$invokeParam = @{
- Parameters = $Parameters.Clone()
- OutPath = Resolve-PSFPath -Path $OutPath
- NoFolder = $NoFolder
- Encoding = $Encoding
- Raw = $Raw
- Silent = $Silent
+ Parameters = $Parameters.Clone()
+ OutPath = Resolve-PSFPath -Path $OutPath
+ NoFolder = $NoFolder
+ Encoding = $Encoding
+ Raw = $Raw
+ Silent = $Silent
+ GenerateObjects = $GenerateObjects
}
foreach ($item in $Template) {
@@ -391,4 +460,4 @@
} -EnableException $EnableException -PSCmdlet $PSCmdlet -Continue
}
}
-}
\ No newline at end of file
+}
diff --git a/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1 b/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
index 67a8a5a..c12e472 100644
--- a/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
+++ b/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
@@ -1,6 +1,5 @@
-function Restart-PSMDShell
-{
- <#
+function Restart-PSMDShell {
+ <#
.SYNOPSIS
A swift way to restart the PowerShell console.
@@ -33,13 +32,8 @@
PS C:\> Restart-PSMDShell -Admin -NoExit
Creates a new PowerShell process, run with elevation, while keeping the current console around.
-
- .NOTES
- Version 1.0.0.0
- Author: Friedrich Weinmann
- Created on: August 6th, 2016
#>
- [Alias('rss', 'Restart-Shell')]
+ [Alias('rss', 'Restart-Shell')]
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')]
Param (
[Switch]
@@ -52,25 +46,36 @@
$NoProfile
)
- begin
- {
- $powershellPath = (Get-Process -id $pid).Path
+ begin {
+ $process = Get-Process -Id $pid
+ $powershellPath = $process.Path
+ $isWindowsTerminal = $process.Parent.ProcessName -eq 'WindowsTerminal'
}
- process
- {
- if ($PSCmdlet.ShouldProcess("Current shell", "Restart"))
- {
- if ($NoProfile)
- {
- if ($Admin) { Start-Process $powershellPath -Verb RunAs -ArgumentList '-NoProfile' }
- else { Start-Process $powershellPath -ArgumentList '-NoProfile' }
+ process {
+ if (-not $PSCmdlet.ShouldProcess("Current shell", "Restart")) { return }
+
+ if ($isWindowsTerminal) {
+ $psVersionName = 'powershell'
+ if ($PSVersionTable.PSVersion.Major -gt 5) { $psVersionName = 'pwsh' }
+
+ $param = @{
+ FilePath = 'wt'
+ ArgumentList = @('-w', 0, 'nt','--title', $psVersionName, $powershellPath)
}
- else
- {
- if ($Admin) { Start-Process $powershellPath -Verb RunAs }
- else { Start-Process $powershellPath }
+ if ($NoProfile) { $param.ArgumentList = @('-w', 0, 'nt', '--title', $psVersionName, $powershellPath, '-NoProfile') }
+ if ($Admin) { $param.Verb = 'RunAs' }
+ Start-Process @param
+ }
+ else {
+ $param = @{
+ FilePath = $powershellPath
}
- if (-not $NoExit) { exit }
+ if ($NoProfile) { $param.ArgumentList = '-NoProfile' }
+ if ($Admin) { $param.Verb = 'RunAs' }
+ Start-Process @param
}
}
+ end {
+ if (-not $NoExit) { exit }
+ }
}
\ No newline at end of file
diff --git a/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml b/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
index 9eaac5a..caff642 100644
--- a/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
+++ b/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
@@ -315,6 +315,41 @@
+
+
+ PSModuleDevelopment.Template.TemplateResult
+
+ PSModuleDevelopment.Template.TemplateResult
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsFolder
+
+
+ Path
+
+
+ Name
+
+
+ IsText
+
+
+
+
+
+
+
PSModuleDevelopment.Utility.LinesOfCode
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj b/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
index 2673b30..b1fa450 100644
--- a/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
@@ -9,8 +9,9 @@
Properties
PSModuleDevelopment
PSModuleDevelopment
- v4.5.2
+ v4.8
512
+
true
@@ -69,6 +70,7 @@
+
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateResult.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateResult.cs
new file mode 100644
index 0000000..27583aa
--- /dev/null
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateResult.cs
@@ -0,0 +1,35 @@
+namespace PSModuleDevelopment.Template
+{
+ ///
+ /// The result object of a template invokation item.
+ /// A project template will generate one such object per file/folder
+ ///
+ public class TemplateResult
+ {
+ ///
+ /// Name of the file or folder
+ ///
+ public string Name;
+ ///
+ /// Path the file or folder should be written to
+ ///
+ public string Path;
+ ///
+ /// The full, resolved path of the item
+ ///
+ public string FullPath;
+ ///
+ /// Any content to write (only viable for files)
+ ///
+ public object Content;
+ ///
+ /// Whether the item to create is a folder or a file
+ ///
+ public bool IsFolder;
+ ///
+ /// Whether the file is a text-file.
+ /// If false, it will be written as a binary file instead.
+ ///
+ public bool IsText = true;
+ }
+}
diff --git a/templates/AzureFunction/function/profile.ps1 b/templates/AzureFunction/function/profile.ps1
index be04a7d..3d09b77 100644
--- a/templates/AzureFunction/function/profile.ps1
+++ b/templates/AzureFunction/function/profile.ps1
@@ -18,115 +18,4 @@ if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts))
# Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell.
# Enable-AzureRmAlias
-# You can also define functions or aliases that can be referenced in any of your PowerShell functions.
-
-function Write-FunctionResult {
- <#
- .SYNOPSIS
- Reports back the output / result of the function app.
-
- .DESCRIPTION
- Reports back the output / result of the function app.
-
- .PARAMETER Status
- Whether the function succeeded or not.
-
- .PARAMETER Body
- Any data to include in the response.
-
- .EXAMPLE
- PS C:\> Write-FunctionResult -Status OK -Body $newUser
-
- Reports success while returning the content of $newUser as output
- #>
- [CmdletBinding()]
- param (
- [Parameter(Mandatory = $true)]
- [System.Net.HttpStatusCode]
- $Status,
-
- [AllowNull()]
- $Body
- )
-
- Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
- StatusCode = $Status
- Body = $Body
- })
-}
-
-function Get-RestParameterValue {
- <#
- .SYNOPSIS
- Extract the exact value of a parameter provided by the user.
-
- .DESCRIPTION
- Extract the exact value of a parameter provided by the user.
- Expects either query or body parameters from the rest call to the http trigger.
-
- .PARAMETER Request
- The request object provided as part of the function call.
-
- .PARAMETER Name
- The name of the parameter to provide.
-
- .EXAMPLE
- PS C:\> Get-RestParameterValue -Request $Request -Name Type
-
- Returns the value of the parameter "Type", as provided by the caller
- #>
- [CmdletBinding()]
- param (
- [Parameter(Mandatory = $true)]
- $Request,
-
- [Parameter(Mandatory = $true)]
- [string]
- $Name
- )
-
- if ($Request.Query.$Name) {
- return $Request.Query.$Name
- }
- $Request.Body.$Name
-}
-
-function Get-RestParameter {
- <#
- .SYNOPSIS
- Parses the rest request parameters for all values matching parameters on the specified command.
-
- .DESCRIPTION
- Parses the rest request parameters for all values matching parameters on the specified command.
- Returns a hashtable ready for splatting.
- Does NOT assert mandatory parameters are specified, so command invocation may fail.
-
- .PARAMETER Request
- The original rest request object, containing the caller's information such as parameters.
-
- .PARAMETER Command
- The command to which to bind input parameters.
-
- .EXAMPLE
- PS C:\> Get-RestParameter -Request $Request -Command Get-AzUser
-
- Retrieves all parameters on the incoming request that match a parameter on Get-AzUser
- #>
- [CmdletBinding()]
- Param (
- [Parameter(Mandatory = $true)]
- $Request,
-
- [Parameter(Mandatory = $true)]
- [string]
- $Command
- )
-
- $commandInfo = Get-Command -Name $Command
- $results = @{ }
- foreach ($parameter in $commandInfo.Parameters.Keys) {
- $value = Get-RestParameterValue -Request $Request -Name $parameter
- if ($null -ne $value) { $results[$parameter] = $value }
- }
- $results
-}
\ No newline at end of file
+# You can also define functions or aliases that can be referenced in any of your PowerShell functions.
\ No newline at end of file
diff --git a/templates/AzureFunction/function/requirements.psd1 b/templates/AzureFunction/function/requirements.psd1
index bf2c583..83d4313 100644
--- a/templates/AzureFunction/function/requirements.psd1
+++ b/templates/AzureFunction/function/requirements.psd1
@@ -1,3 +1,10 @@
@{
- Az = '1.*'
+ # Do you really need ALL of the AZ modules?
+ # Az = '1.*'
+
+ # If you only need Key Vault access, this is your choice
+ # 'Az.KeyVault' = '4.*'
+
+ # Basic tools used in your function app
+ 'Azure.Function.Tools' = '1.*'
}
\ No newline at end of file
diff --git a/templates/MiniModule/.github/FUNDING.yml b/templates/MiniModule/.github/FUNDING.yml
new file mode 100644
index 0000000..ddf3214
--- /dev/null
+++ b/templates/MiniModule/.github/FUNDING.yml
@@ -0,0 +1,13 @@
+# These are supported funding model platforms
+
+github:
+ FriedrichWeinmann
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/templates/MiniModule/.github/workflows/build.yml b/templates/MiniModule/.github/workflows/build.yml
new file mode 100644
index 0000000..80cac05
--- /dev/null
+++ b/templates/MiniModule/.github/workflows/build.yml
@@ -0,0 +1,23 @@
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+
+ runs-on: windows-2019
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install Prerequisites
+ run: .\build\vsts-prerequisites.ps1
+ shell: powershell
+ - name: Validate
+ run: .\build\vsts-validate.ps1
+ shell: powershell
+ - name: Build
+ run: .\build\vsts-build.ps1 -ApiKey $env:APIKEY
+ shell: powershell
+ env:
+ APIKEY: ${{ secrets.ApiKey }}
\ No newline at end of file
diff --git a/templates/MiniModule/.github/workflows/validate.yml b/templates/MiniModule/.github/workflows/validate.yml
new file mode 100644
index 0000000..0b516ce
--- /dev/null
+++ b/templates/MiniModule/.github/workflows/validate.yml
@@ -0,0 +1,15 @@
+on: [pull_request]
+
+jobs:
+ validate:
+
+ runs-on: windows-2019
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install Prerequisites
+ run: .\build\vsts-prerequisites.ps1
+ shell: powershell
+ - name: Validate
+ run: .\build\vsts-validate.ps1
+ shell: powershell
\ No newline at end of file
diff --git a/templates/MiniModule/LICENSE b/templates/MiniModule/LICENSE
new file mode 100644
index 0000000..89a8466
--- /dev/null
+++ b/templates/MiniModule/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) þ!year!þ þauthorþ
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/templates/MiniModule/PSMDInvoke.ps1 b/templates/MiniModule/PSMDInvoke.ps1
new file mode 100644
index 0000000..20836b6
--- /dev/null
+++ b/templates/MiniModule/PSMDInvoke.ps1
@@ -0,0 +1,4 @@
+param (
+ $Path
+)
+New-PSMDTemplate -ReferencePath "$PSScriptRoot" -OutPath $Path
\ No newline at end of file
diff --git a/templates/MiniModule/PSMDTemplate.ps1 b/templates/MiniModule/PSMDTemplate.ps1
new file mode 100644
index 0000000..812fbcb
--- /dev/null
+++ b/templates/MiniModule/PSMDTemplate.ps1
@@ -0,0 +1,17 @@
+@{
+ TemplateName = 'MiniModule'
+ Version = "1.0.0.0"
+ AutoIncrementVersion = $true
+ Tags = 'module'
+ Author = 'Friedrich Weinmann'
+ Description = 'Module scaffold with full CI/CD support and minimal dependencies'
+ Exclusions = @("PSMDInvoke.ps1") # Contains list of files - relative path to root - to ignore when building the template
+ Scripts = @{
+ guid = {
+ [System.Guid]::NewGuid().ToString()
+ }
+ year = {
+ Get-Date -Format "yyyy"
+ }
+ }
+}
\ No newline at end of file
diff --git a/templates/MiniModule/build/vsts-build.ps1 b/templates/MiniModule/build/vsts-build.ps1
new file mode 100644
index 0000000..218e4bb
--- /dev/null
+++ b/templates/MiniModule/build/vsts-build.ps1
@@ -0,0 +1,98 @@
+<#
+This script publishes the module to the gallery.
+It expects as input an ApiKey authorized to publish the module.
+
+Insert any build steps you may need to take before publishing it here.
+#>
+param (
+ $ApiKey,
+
+ $WorkingDirectory,
+
+ $Repository = 'PSGallery',
+
+ [switch]
+ $LocalRepo,
+
+ [switch]
+ $SkipPublish,
+
+ [switch]
+ $AutoVersion
+)
+
+#region Handle Working Directory Defaults
+if (-not $WorkingDirectory)
+{
+ if ($env:RELEASE_PRIMARYARTIFACTSOURCEALIAS)
+ {
+ $WorkingDirectory = Join-Path -Path $env:SYSTEM_DEFAULTWORKINGDIRECTORY -ChildPath $env:RELEASE_PRIMARYARTIFACTSOURCEALIAS
+ }
+ else { $WorkingDirectory = $env:SYSTEM_DEFAULTWORKINGDIRECTORY }
+}
+if (-not $WorkingDirectory) { $WorkingDirectory = Split-Path $PSScriptRoot }
+#endregion Handle Working Directory Defaults
+
+# Prepare publish folder
+Write-Host "Creating and populating publishing directory"
+$publishDir = New-Item -Path $WorkingDirectory -Name publish -ItemType Directory -Force
+Copy-Item -Path "$($WorkingDirectory)\þnameþ" -Destination $publishDir.FullName -Recurse -Force
+
+#region Gather text data to compile
+$text = @()
+
+# Gather commands
+Get-ChildItem -Path "$($publishDir.FullName)\þnameþ\internal\functions\" -Recurse -File -Filter "*.ps1" | ForEach-Object {
+ $text += [System.IO.File]::ReadAllText($_.FullName)
+}
+Get-ChildItem -Path "$($publishDir.FullName)\þnameþ\functions\" -Recurse -File -Filter "*.ps1" | ForEach-Object {
+ $text += [System.IO.File]::ReadAllText($_.FullName)
+}
+
+# Gather scripts
+Get-ChildItem -Path "$($publishDir.FullName)\þnameþ\internal\scripts\" -Recurse -File -Filter "*.ps1" | ForEach-Object {
+ $text += [System.IO.File]::ReadAllText($_.FullName)
+}
+
+#region Update the psm1 file & Cleanup
+[System.IO.File]::WriteAllText("$($publishDir.FullName)\þnameþ\þnameþ.psm1", ($text -join "`n`n"), [System.Text.Encoding]::UTF8)
+Remove-Item -Path "$($publishDir.FullName)\þnameþ\internal" -Recurse -Force
+Remove-Item -Path "$($publishDir.FullName)\þnameþ\functions" -Recurse -Force
+#endregion Update the psm1 file & Cleanup
+
+#region Updating the Module Version
+if ($AutoVersion)
+{
+ Write-Host "Updating module version numbers."
+ try { [version]$remoteVersion = (Find-Module 'þnameþ' -Repository $Repository -ErrorAction Stop).Version }
+ catch
+ {
+ throw "Failed to access $($Repository) : $_"
+ }
+ if (-not $remoteVersion)
+ {
+ throw "Couldn't find þnameþ on repository $($Repository) : $_"
+ }
+ $newBuildNumber = $remoteVersion.Build + 1
+ [version]$localVersion = (Import-PowerShellDataFile -Path "$($publishDir.FullName)\þnameþ\þnameþ.psd1").ModuleVersion
+ Update-ModuleManifest -Path "$($publishDir.FullName)\þnameþ\þnameþ.psd1" -ModuleVersion "$($localVersion.Major).$($localVersion.Minor).$($newBuildNumber)"
+}
+#endregion Updating the Module Version
+
+#region Publish
+if ($SkipPublish) { return }
+if ($LocalRepo)
+{
+ # Dependencies must go first
+ Write-Host "Creating Nuget Package for module: PSFramework"
+ New-PSMDModuleNugetPackage -ModulePath (Get-Module -Name PSFramework).ModuleBase -PackagePath .
+ Write-Host "Creating Nuget Package for module: þnameþ"
+ New-PSMDModuleNugetPackage -ModulePath "$($publishDir.FullName)\þnameþ" -PackagePath .
+}
+else
+{
+ # Publish to Gallery
+ Write-Host "Publishing the þnameþ module to $($Repository)"
+ Publish-Module -Path "$($publishDir.FullName)\þnameþ" -NuGetApiKey $ApiKey -Force -Repository $Repository
+}
+#endregion Publish
\ No newline at end of file
diff --git a/templates/MiniModule/build/vsts-prerequisites.ps1 b/templates/MiniModule/build/vsts-prerequisites.ps1
new file mode 100644
index 0000000..1746aff
--- /dev/null
+++ b/templates/MiniModule/build/vsts-prerequisites.ps1
@@ -0,0 +1,25 @@
+param (
+ [string]
+ $Repository = 'PSGallery'
+)
+
+$modules = @("Pester", "PSScriptAnalyzer")
+
+# Automatically add missing dependencies
+$data = Import-PowerShellDataFile -Path "$PSScriptRoot\..\þnameþ\þnameþ.psd1"
+foreach ($dependency in $data.RequiredModules) {
+ if ($dependency -is [string]) {
+ if ($modules -contains $dependency) { continue }
+ $modules += $dependency
+ }
+ else {
+ if ($modules -contains $dependency.ModuleName) { continue }
+ $modules += $dependency.ModuleName
+ }
+}
+
+foreach ($module in $modules) {
+ Write-Host "Installing $module" -ForegroundColor Cyan
+ Install-Module $module -Force -SkipPublisherCheck -Repository $Repository
+ Import-Module $module -Force -PassThru
+}
\ No newline at end of file
diff --git a/templates/MiniModule/build/vsts-validate.ps1 b/templates/MiniModule/build/vsts-validate.ps1
new file mode 100644
index 0000000..1ad4c70
--- /dev/null
+++ b/templates/MiniModule/build/vsts-validate.ps1
@@ -0,0 +1,2 @@
+# Run internal pester tests
+& "$PSScriptRoot\..\tests\pester.ps1"
\ No newline at end of file
diff --git a/templates/MiniModule/readme.md b/templates/MiniModule/readme.md
new file mode 100644
index 0000000..32e8e0c
--- /dev/null
+++ b/templates/MiniModule/readme.md
@@ -0,0 +1,3 @@
+# þnameþ
+
+ADD DESCRIPTION HERE
diff --git a/templates/MiniModule/tests/functions/readme.md b/templates/MiniModule/tests/functions/readme.md
new file mode 100644
index 0000000..f2b2ef0
--- /dev/null
+++ b/templates/MiniModule/tests/functions/readme.md
@@ -0,0 +1,7 @@
+# Description
+
+This is where the function tests go.
+
+Make sure to put them in folders reflecting the actual module structure.
+
+It is not necessary to differentiate between internal and public functions here.
\ No newline at end of file
diff --git a/templates/MiniModule/tests/general/FileIntegrity.Exceptions.ps1 b/templates/MiniModule/tests/general/FileIntegrity.Exceptions.ps1
new file mode 100644
index 0000000..0d92e79
--- /dev/null
+++ b/templates/MiniModule/tests/general/FileIntegrity.Exceptions.ps1
@@ -0,0 +1,31 @@
+# List of forbidden commands
+$global:BannedCommands = @(
+ 'Write-Output'
+
+ # Use CIM instead where possible
+ 'Get-WmiObject'
+ 'Invoke-WmiMethod'
+ 'Register-WmiEvent'
+ 'Remove-WmiObject'
+ 'Set-WmiInstance'
+
+ # Use Get-WinEvent instead
+ 'Get-EventLog'
+)
+
+<#
+ Contains list of exceptions for banned cmdlets.
+ Insert the file names of files that may contain them.
+
+ Example:
+ "Write-Host" = @('Write-PSFHostColor.ps1','Write-PSFMessage.ps1')
+#>
+$global:MayContainCommand = @{
+ "Write-Host" = @()
+ "Write-Verbose" = @()
+ "Write-Warning" = @()
+ "Write-Error" = @()
+ "Write-Output" = @()
+ "Write-Information" = @()
+ "Write-Debug" = @()
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/general/FileIntegrity.Tests.ps1 b/templates/MiniModule/tests/general/FileIntegrity.Tests.ps1
new file mode 100644
index 0000000..8656e65
--- /dev/null
+++ b/templates/MiniModule/tests/general/FileIntegrity.Tests.ps1
@@ -0,0 +1,95 @@
+$moduleRoot = (Resolve-Path "$global:testroot\..").Path
+
+. "$global:testroot\general\FileIntegrity.Exceptions.ps1"
+
+Describe "Verifying integrity of module files" {
+ BeforeAll {
+ function Get-FileEncoding
+ {
+ <#
+ .SYNOPSIS
+ Tests a file for encoding.
+
+ .DESCRIPTION
+ Tests a file for encoding.
+
+ .PARAMETER Path
+ The file to test
+ #>
+ [CmdletBinding()]
+ Param (
+ [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
+ [Alias('FullName')]
+ [string]
+ $Path
+ )
+
+ if ($PSVersionTable.PSVersion.Major -lt 6)
+ {
+ [byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path
+ }
+ else
+ {
+ [byte[]]$byte = Get-Content -AsByteStream -ReadCount 4 -TotalCount 4 -Path $Path
+ }
+
+ if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) { 'UTF8 BOM' }
+ elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) { 'Unicode' }
+ elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff) { 'UTF32' }
+ elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76) { 'UTF7' }
+ else { 'Unknown' }
+ }
+ }
+
+ Context "Validating PS1 Script files" {
+ $allFiles = Get-ChildItem -Path $moduleRoot -Recurse | Where-Object Name -like "*.ps1" | Where-Object FullName -NotLike "$moduleRoot\tests\*"
+
+ foreach ($file in $allFiles)
+ {
+ $name = $file.FullName.Replace("$moduleRoot\", '')
+
+ It "[$name] Should have UTF8 encoding with Byte Order Mark" -TestCases @{ file = $file } {
+ Get-FileEncoding -Path $file.FullName | Should -Be 'UTF8 BOM'
+ }
+
+ It "[$name] Should have no trailing space" -TestCases @{ file = $file } {
+ ($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0}).LineNumber | Should -BeNullOrEmpty
+ }
+
+ $tokens = $null
+ $parseErrors = $null
+ $null = [System.Management.Automation.Language.Parser]::ParseFile($file.FullName, [ref]$tokens, [ref]$parseErrors)
+
+ It "[$name] Should have no syntax errors" -TestCases @{ parseErrors = $parseErrors } {
+ $parseErrors | Should -BeNullOrEmpty
+ }
+
+ foreach ($command in $global:BannedCommands)
+ {
+ if ($global:MayContainCommand["$command"] -notcontains $file.Name)
+ {
+ It "[$name] Should not use $command" -TestCases @{ tokens = $tokens; command = $command } {
+ $tokens | Where-Object Text -EQ $command | Should -BeNullOrEmpty
+ }
+ }
+ }
+ }
+ }
+
+ Context "Validating help.txt help files" {
+ $allFiles = Get-ChildItem -Path $moduleRoot -Recurse | Where-Object Name -like "*.help.txt" | Where-Object FullName -NotLike "$moduleRoot\tests\*"
+
+ foreach ($file in $allFiles)
+ {
+ $name = $file.FullName.Replace("$moduleRoot\", '')
+
+ It "[$name] Should have UTF8 encoding" -TestCases @{ file = $file } {
+ Get-FileEncoding -Path $file.FullName | Should -Be 'UTF8 BOM'
+ }
+
+ It "[$name] Should have no trailing space" -TestCases @{ file = $file } {
+ ($file | Select-String "\s$" | Where-Object { $_.Line.Trim().Length -gt 0 } | Measure-Object).Count | Should -Be 0
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/general/Help.Exceptions.ps1 b/templates/MiniModule/tests/general/Help.Exceptions.ps1
new file mode 100644
index 0000000..f9c9bd7
--- /dev/null
+++ b/templates/MiniModule/tests/general/Help.Exceptions.ps1
@@ -0,0 +1,26 @@
+# List of functions that should be ignored
+$global:FunctionHelpTestExceptions = @(
+
+)
+
+<#
+ List of arrayed enumerations. These need to be treated differently. Add full name.
+ Example:
+
+ "Sqlcollaborative.Dbatools.Connection.ManagementConnectionType[]"
+#>
+$global:HelpTestEnumeratedArrays = @(
+
+)
+
+<#
+ Some types on parameters just fail their validation no matter what.
+ For those it becomes possible to skip them, by adding them to this hashtable.
+ Add by following this convention: = @()
+ Example:
+
+ "Get-DbaCmObject" = @("DoNotUse")
+#>
+$global:HelpTestSkipParameterType = @{
+
+}
diff --git a/templates/MiniModule/tests/general/Help.Tests.ps1 b/templates/MiniModule/tests/general/Help.Tests.ps1
new file mode 100644
index 0000000..f1dc4d3
--- /dev/null
+++ b/templates/MiniModule/tests/general/Help.Tests.ps1
@@ -0,0 +1,152 @@
+<#
+ .NOTES
+ The original test this is based upon was written by June Blender.
+ After several rounds of modifications it stands now as it is, but the honor remains hers.
+
+ Thank you June, for all you have done!
+
+ .DESCRIPTION
+ This test evaluates the help for all commands in a module.
+
+ .PARAMETER SkipTest
+ Disables this test.
+
+ .PARAMETER CommandPath
+ List of paths under which the script files are stored.
+ This test assumes that all functions have their own file that is named after themselves.
+ These paths are used to search for commands that should exist and be tested.
+ Will search recursively and accepts wildcards, make sure only functions are found
+
+ .PARAMETER ModuleName
+ Name of the module to be tested.
+ The module must already be imported
+
+ .PARAMETER ExceptionsFile
+ File in which exceptions and adjustments are configured.
+ In it there should be two arrays and a hashtable defined:
+ $global:FunctionHelpTestExceptions
+ $global:HelpTestEnumeratedArrays
+ $global:HelpTestSkipParameterType
+ These can be used to tweak the tests slightly in cases of need.
+ See the example file for explanations on each of these usage and effect.
+#>
+[CmdletBinding()]
+Param (
+ [switch]
+ $SkipTest,
+
+ [string[]]
+ $CommandPath = @("$global:testroot\..\þnameþ\functions", "$global:testroot\..\þnameþ\internal\functions"),
+
+ [string]
+ $ModuleName = "þnameþ",
+
+ [string]
+ $ExceptionsFile = "$global:testroot\general\Help.Exceptions.ps1"
+)
+if ($SkipTest) { return }
+. $ExceptionsFile
+
+$CommandPath = @(
+ "$global:testroot\..\þnameþ\functions"
+ "$global:testroot\..\þnameþ\internal\functions"
+)
+
+$includedNames = foreach ($path in $CommandPath) { (Get-ChildItem $path -Recurse -File | Where-Object Name -like "*.ps1").BaseName }
+$commandTypes = @('Cmdlet', 'Function')
+if ($PSVersionTable.PSEdition -eq 'Desktop' ) { $commandTypes += 'Workflow' }
+$commands = Get-Command -Module (Get-Module $ModuleName) -CommandType $commandTypes | Where-Object Name -In $includedNames
+
+## When testing help, remember that help is cached at the beginning of each session.
+## To test, restart session.
+
+
+foreach ($command in $commands) {
+ $commandName = $command.Name
+
+ # Skip all functions that are on the exclusions list
+ if ($global:FunctionHelpTestExceptions -contains $commandName) { continue }
+
+ # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets
+ $Help = Get-Help $commandName -ErrorAction SilentlyContinue
+
+ Describe "Test help for $commandName" {
+
+ # If help is not found, synopsis in auto-generated help is the syntax diagram
+ It "should not be auto-generated" -TestCases @{ Help = $Help } {
+ $Help.Synopsis | Should -Not -BeLike '*`[``]*'
+ }
+
+ # Should be a description for every function
+ It "gets description for $commandName" -TestCases @{ Help = $Help } {
+ $Help.Description | Should -Not -BeNullOrEmpty
+ }
+
+ # Should be at least one example
+ It "gets example code from $commandName" -TestCases @{ Help = $Help } {
+ ($Help.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty
+ }
+
+ # Should be at least one example description
+ It "gets example help from $commandName" -TestCases @{ Help = $Help } {
+ ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should -Not -BeNullOrEmpty
+ }
+
+ Context "Test parameter help for $commandName" {
+
+ $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
+
+ $parameters = $command.ParameterSets.Parameters | Sort-Object -Property Name -Unique | Where-Object Name -notin $common
+ $parameterNames = $parameters.Name
+ $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique
+ foreach ($parameter in $parameters) {
+ $parameterName = $parameter.Name
+ $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName
+
+ # Should be a description for every parameter
+ It "gets help for parameter: $parameterName : in $commandName" -TestCases @{ parameterHelp = $parameterHelp } {
+ $parameterHelp.Description.Text | Should -Not -BeNullOrEmpty
+ }
+
+ $codeMandatory = $parameter.IsMandatory.toString()
+ It "help for $parameterName parameter in $commandName has correct Mandatory value" -TestCases @{ parameterHelp = $parameterHelp; codeMandatory = $codeMandatory } {
+ $parameterHelp.Required | Should -Be $codeMandatory
+ }
+
+ if ($HelpTestSkipParameterType[$commandName] -contains $parameterName) { continue }
+
+ $codeType = $parameter.ParameterType.Name
+
+ if ($parameter.ParameterType.IsEnum) {
+ # Enumerations often have issues with the typename not being reliably available
+ $names = $parameter.ParameterType::GetNames($parameter.ParameterType)
+ # Parameter type in Help should match code
+ It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ parameterHelp = $parameterHelp; names = $names } {
+ $parameterHelp.parameterValueGroup.parameterValue | Should -be $names
+ }
+ }
+ elseif ($parameter.ParameterType.FullName -in $HelpTestEnumeratedArrays) {
+ # Enumerations often have issues with the typename not being reliably available
+ $names = [Enum]::GetNames($parameter.ParameterType.DeclaredMembers[0].ReturnType)
+ It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ parameterHelp = $parameterHelp; names = $names } {
+ $parameterHelp.parameterValueGroup.parameterValue | Should -be $names
+ }
+ }
+ else {
+ # To avoid calling Trim method on a null object.
+ $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() }
+ # Parameter type in Help should match code
+ It "help for $commandName has correct parameter type for $parameterName" -TestCases @{ helpType = $helpType; codeType = $codeType } {
+ $helpType | Should -be $codeType
+ }
+ }
+ }
+ foreach ($helpParm in $HelpParameterNames) {
+ # Shouldn't find extra parameters in help.
+ It "finds help parameter in code: $helpParm" -TestCases @{ helpParm = $helpParm; parameterNames = $parameterNames } {
+ $helpParm -in $parameterNames | Should -Be $true
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/general/Manifest.Tests.ps1 b/templates/MiniModule/tests/general/Manifest.Tests.ps1
new file mode 100644
index 0000000..215f3b7
--- /dev/null
+++ b/templates/MiniModule/tests/general/Manifest.Tests.ps1
@@ -0,0 +1,62 @@
+Describe "Validating the module manifest" {
+ $moduleRoot = (Resolve-Path "$global:testroot\..\þnameþ").Path
+ $manifest = ((Get-Content "$moduleRoot\þnameþ.psd1") -join "`n") | Invoke-Expression
+ Context "Basic resources validation" {
+ $files = Get-ChildItem "$moduleRoot\functions" -Recurse -File | Where-Object Name -like "*.ps1"
+ It "Exports all functions in the public folder" -TestCases @{ files = $files; manifest = $manifest } {
+
+ $functions = (Compare-Object -ReferenceObject $files.BaseName -DifferenceObject $manifest.FunctionsToExport | Where-Object SideIndicator -Like '<=').InputObject
+ $functions | Should -BeNullOrEmpty
+ }
+ It "Exports no function that isn't also present in the public folder" -TestCases @{ files = $files; manifest = $manifest } {
+ $functions = (Compare-Object -ReferenceObject $files.BaseName -DifferenceObject $manifest.FunctionsToExport | Where-Object SideIndicator -Like '=>').InputObject
+ $functions | Should -BeNullOrEmpty
+ }
+
+ It "Exports none of its internal functions" -TestCases @{ moduleRoot = $moduleRoot; manifest = $manifest } {
+ $files = Get-ChildItem "$moduleRoot\internal\functions" -Recurse -File -Filter "*.ps1"
+ $files | Where-Object BaseName -In $manifest.FunctionsToExport | Should -BeNullOrEmpty
+ }
+ }
+
+ Context "Individual file validation" {
+ It "The root module file exists" -TestCases @{ moduleRoot = $moduleRoot; manifest = $manifest } {
+ Test-Path "$moduleRoot\$($manifest.RootModule)" | Should -Be $true
+ }
+
+ foreach ($format in $manifest.FormatsToProcess)
+ {
+ It "The file $format should exist" -TestCases @{ moduleRoot = $moduleRoot; format = $format } {
+ Test-Path "$moduleRoot\$format" | Should -Be $true
+ }
+ }
+
+ foreach ($type in $manifest.TypesToProcess)
+ {
+ It "The file $type should exist" -TestCases @{ moduleRoot = $moduleRoot; type = $type } {
+ Test-Path "$moduleRoot\$type" | Should -Be $true
+ }
+ }
+
+ foreach ($assembly in $manifest.RequiredAssemblies)
+ {
+ if ($assembly -like "*.dll") {
+ It "The file $assembly should exist" -TestCases @{ moduleRoot = $moduleRoot; assembly = $assembly } {
+ Test-Path "$moduleRoot\$assembly" | Should -Be $true
+ }
+ }
+ else {
+ It "The file $assembly should load from the GAC" -TestCases @{ moduleRoot = $moduleRoot; assembly = $assembly } {
+ { Add-Type -AssemblyName $assembly } | Should -Not -Throw
+ }
+ }
+ }
+
+ foreach ($tag in $manifest.PrivateData.PSData.Tags)
+ {
+ It "Tags should have no spaces in name" -TestCases @{ tag = $tag } {
+ $tag -match " " | Should -Be $false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/general/PSScriptAnalyzer.Tests.ps1 b/templates/MiniModule/tests/general/PSScriptAnalyzer.Tests.ps1
new file mode 100644
index 0000000..1686112
--- /dev/null
+++ b/templates/MiniModule/tests/general/PSScriptAnalyzer.Tests.ps1
@@ -0,0 +1,40 @@
+[CmdletBinding()]
+Param (
+ [switch]
+ $SkipTest,
+
+ [string[]]
+ $CommandPath = @("$global:testroot\..\þnameþ\functions", "$global:testroot\..\þnameþ\internal\functions")
+)
+
+if ($SkipTest) { return }
+
+$global:__pester_data.ScriptAnalyzer = New-Object System.Collections.ArrayList
+
+Describe 'Invoking PSScriptAnalyzer against commandbase' {
+ $commandFiles = foreach ($path in $CommandPath) { Get-ChildItem -Path $path -Recurse | Where-Object Name -like "*.ps1" }
+ $scriptAnalyzerRules = Get-ScriptAnalyzerRule
+
+ foreach ($file in $commandFiles)
+ {
+ Context "Analyzing $($file.BaseName)" {
+ $analysis = Invoke-ScriptAnalyzer -Path $file.FullName -ExcludeRule PSAvoidTrailingWhitespace, PSShouldProcess
+
+ forEach ($rule in $scriptAnalyzerRules)
+ {
+ It "Should pass $rule" -TestCases @{ analysis = $analysis; rule = $rule } {
+ If ($analysis.RuleName -contains $rule)
+ {
+ $analysis | Where-Object RuleName -EQ $rule -outvariable failures | ForEach-Object { $null = $global:__pester_data.ScriptAnalyzer.Add($_) }
+
+ 1 | Should -Be 0
+ }
+ else
+ {
+ 0 | Should -Be 0
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/pester.ps1 b/templates/MiniModule/tests/pester.ps1
new file mode 100644
index 0000000..d2785eb
--- /dev/null
+++ b/templates/MiniModule/tests/pester.ps1
@@ -0,0 +1,113 @@
+param (
+ $TestGeneral = $true,
+
+ $TestFunctions = $true,
+
+ [ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')]
+ [Alias('Show')]
+ $Output = "None",
+
+ $Include = "*",
+
+ $Exclude = ""
+)
+
+Write-Host "Starting Tests"
+
+Write-Host "Importing Module"
+
+$global:testroot = $PSScriptRoot
+$global:__pester_data = @{ }
+
+Remove-Module þnameþ -ErrorAction Ignore
+Import-Module "$PSScriptRoot\..\þnameþ\þnameþ.psd1"
+Import-Module "$PSScriptRoot\..\þnameþ\þnameþ.psm1" -Force
+
+# Need to import explicitly so we can use the configuration class
+Import-Module Pester
+
+Write-Host "Creating test result folder"
+$null = New-Item -Path "$PSScriptRoot\.." -Name TestResults -ItemType Directory -Force
+
+$totalFailed = 0
+$totalRun = 0
+
+$testresults = @()
+$config = [PesterConfiguration]::Default
+$config.TestResult.Enabled = $true
+
+#region Run General Tests
+if ($TestGeneral)
+{
+ Write-Host "Modules imported, proceeding with general tests"
+ foreach ($file in (Get-ChildItem "$PSScriptRoot\general" | Where-Object Name -like "*.Tests.ps1"))
+ {
+ if ($file.Name -notlike $Include) { continue }
+ if ($file.Name -like $Exclude) { continue }
+
+ Write-Host " Executing $($file.Name)"
+ $config.TestResult.OutputPath = Join-Path "$PSScriptRoot\..\TestResults" "TEST-$($file.BaseName).xml"
+ $config.Run.Path = $file.FullName
+ $config.Run.PassThru = $true
+ $config.Output.Verbosity = $Output
+ $results = Invoke-Pester -Configuration $config
+ foreach ($result in $results)
+ {
+ $totalRun += $result.TotalCount
+ $totalFailed += $result.FailedCount
+ $result.Tests | Where-Object Result -ne 'Passed' | ForEach-Object {
+ $testresults += [pscustomobject]@{
+ Block = $_.Block
+ Name = "It $($_.Name)"
+ Result = $_.Result
+ Message = $_.ErrorRecord.DisplayErrorMessage
+ }
+ }
+ }
+ }
+}
+#endregion Run General Tests
+
+$global:__pester_data.ScriptAnalyzer | Out-Host
+
+#region Test Commands
+if ($TestFunctions)
+{
+ Write-Host "Proceeding with individual tests"
+ foreach ($file in (Get-ChildItem "$PSScriptRoot\functions" -Recurse -File | Where-Object Name -like "*Tests.ps1"))
+ {
+ if ($file.Name -notlike $Include) { continue }
+ if ($file.Name -like $Exclude) { continue }
+
+ Write-Host " Executing $($file.Name)"
+ $config.TestResult.OutputPath = Join-Path "$PSScriptRoot\..\TestResults" "TEST-$($file.BaseName).xml"
+ $config.Run.Path = $file.FullName
+ $config.Run.PassThru = $true
+ $config.Output.Verbosity = $Output
+ $results = Invoke-Pester -Configuration $config
+ foreach ($result in $results)
+ {
+ $totalRun += $result.TotalCount
+ $totalFailed += $result.FailedCount
+ $result.Tests | Where-Object Result -ne 'Passed' | ForEach-Object {
+ $testresults += [pscustomobject]@{
+ Block = $_.Block
+ Name = "It $($_.Name)"
+ Result = $_.Result
+ Message = $_.ErrorRecord.DisplayErrorMessage
+ }
+ }
+ }
+ }
+}
+#endregion Test Commands
+
+$testresults | Sort-Object Describe, Context, Name, Result, Message | Format-List
+
+if ($totalFailed -eq 0) { Write-Host "All $totalRun tests executed without a single failure!" }
+else { Write-Host "$totalFailed tests out of $totalRun tests failed!" }
+
+if ($totalFailed -gt 0)
+{
+ throw "$totalFailed / $totalRun tests failed!"
+}
\ No newline at end of file
diff --git a/templates/MiniModule/tests/readme.md b/templates/MiniModule/tests/readme.md
new file mode 100644
index 0000000..43bb2fa
--- /dev/null
+++ b/templates/MiniModule/tests/readme.md
@@ -0,0 +1,31 @@
+# Description
+
+This is the folder, where all the tests go.
+
+Those are subdivided in two categories:
+
+ - General
+ - Function
+
+## General Tests
+
+General tests are function generic and test for general policies.
+
+These test scan answer questions such as:
+
+ - Is my module following my style guides?
+ - Does any of my scripts have a syntax error?
+ - Do my scripts use commands I do not want them to use?
+ - Do my commands follow best practices?
+ - Do my commands have proper help?
+
+Basically, these allow a general module health check.
+
+These tests are already provided as part of the template.
+
+## Function Tests
+
+A healthy module should provide unit and integration tests for the commands & components it ships.
+Only then can be guaranteed, that they will actually perform as promised.
+
+However, as each such test must be specific to the function it tests, there cannot be much in the way of templates.
\ No newline at end of file
diff --git "a/templates/MiniModule/\303\276name\303\276/LICENSE" "b/templates/MiniModule/\303\276name\303\276/LICENSE"
new file mode 100644
index 0000000..89a8466
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/LICENSE"
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) þ!year!þ þauthorþ
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git "a/templates/MiniModule/\303\276name\303\276/functions/readme.md" "b/templates/MiniModule/\303\276name\303\276/functions/readme.md"
new file mode 100644
index 0000000..105038b
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/functions/readme.md"
@@ -0,0 +1,3 @@
+# Functions
+
+Folder for all the functions the user is supposed to have access to.
diff --git "a/templates/MiniModule/\303\276name\303\276/internal/functions/readme.md" "b/templates/MiniModule/\303\276name\303\276/internal/functions/readme.md"
new file mode 100644
index 0000000..0643487
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/internal/functions/readme.md"
@@ -0,0 +1,3 @@
+# Internal > Functions
+
+Folder for all the functions you want the user to not see.
diff --git "a/templates/MiniModule/\303\276name\303\276/internal/scripts/readme.md" "b/templates/MiniModule/\303\276name\303\276/internal/scripts/readme.md"
new file mode 100644
index 0000000..2a21053
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/internal/scripts/readme.md"
@@ -0,0 +1,3 @@
+# Internal > Scripts
+
+Put in all the scripts that should be run once during import
diff --git "a/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psd1" "b/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psd1"
new file mode 100644
index 0000000..4cb69cd
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psd1"
@@ -0,0 +1,126 @@
+@{
+
+# Script module or binary module file associated with this manifest.
+RootModule = 'þnameþ.psm1'
+
+# Version number of this module.
+ModuleVersion = '1.0.0'
+
+# Supported PSEditions
+# CompatiblePSEditions = @()
+
+# ID used to uniquely identify this module
+GUID = 'þ!guid!þ'
+
+# Author of this module
+Author = 'þauthorþ'
+
+# Company or vendor of this module
+CompanyName = 'þcompanyþ'
+
+# Copyright statement for this module
+Copyright = '(c) þauthorþ. All rights reserved.'
+
+# Description of the functionality provided by this module
+Description = 'þdescriptionþ'
+
+# Minimum version of the PowerShell engine required by this module
+# PowerShellVersion = ''
+
+# Name of the PowerShell host required by this module
+# PowerShellHostName = ''
+
+# Minimum version of the PowerShell host required by this module
+# PowerShellHostVersion = ''
+
+# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
+# DotNetFrameworkVersion = ''
+
+# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
+# ClrVersion = ''
+
+# Processor architecture (None, X86, Amd64) required by this module
+# ProcessorArchitecture = ''
+
+# Modules that must be imported into the global environment prior to importing this module
+# RequiredModules = @()
+
+# Assemblies that must be loaded prior to importing this module
+# RequiredAssemblies = @()
+
+# Script files (.ps1) that are run in the caller's environment prior to importing this module.
+# ScriptsToProcess = @()
+
+# Type files (.ps1xml) to be loaded when importing this module
+# TypesToProcess = @()
+
+# Format files (.ps1xml) to be loaded when importing this module
+# FormatsToProcess = @()
+
+# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
+# NestedModules = @()
+
+# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
+FunctionsToExport = @(
+
+)
+
+# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
+# CmdletsToExport = '*'
+
+# Variables to export from this module
+# VariablesToExport = '*'
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+# AliasesToExport = '*'
+
+# DSC resources to export from this module
+# DscResourcesToExport = @()
+
+# List of all modules packaged with this module
+# ModuleList = @()
+
+# List of all files packaged with this module
+# FileList = @()
+
+# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
+PrivateData = @{
+
+ PSData = @{
+
+ # Tags applied to this module. These help with module discovery in online galleries.
+ # Tags = @()
+
+ # A URL to the license for this module.
+ # LicenseUri = ''
+
+ # A URL to the main website for this project.
+ # ProjectUri = ''
+
+ # A URL to an icon representing this module.
+ # IconUri = ''
+
+ # ReleaseNotes of this module
+ # ReleaseNotes = ''
+
+ # Prerelease string of this module
+ # Prerelease = ''
+
+ # Flag to indicate whether the module requires explicit user acceptance for install/update/save
+ # RequireLicenseAcceptance = $false
+
+ # External dependent modules of this module
+ # ExternalModuleDependencies = @()
+
+ } # End of PSData hashtable
+
+} # End of PrivateData hashtable
+
+# HelpInfo URI of this module
+# HelpInfoURI = ''
+
+# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
+# DefaultCommandPrefix = ''
+
+}
+
diff --git "a/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psm1" "b/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psm1"
new file mode 100644
index 0000000..2681965
--- /dev/null
+++ "b/templates/MiniModule/\303\276name\303\276/\303\276name\303\276.psm1"
@@ -0,0 +1,11 @@
+foreach ($file in Get-ChildItem -Path "$PSScriptRoot/internal/functions" -Filter *.ps1 -Recurse) {
+ . $file.FullName
+}
+
+foreach ($file in Get-ChildItem -Path "$PSScriptRoot/functions" -Filter *.ps1 -Recurse) {
+ . $file.FullName
+}
+
+foreach ($file in Get-ChildItem -Path "$PSScriptRoot/internal/scripts" -Filter *.ps1 -Recurse) {
+ . $file.FullName
+}
\ No newline at end of file