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