diff --git a/PSModuleDevelopment/PSModuleDevelopment.psd1 b/PSModuleDevelopment/PSModuleDevelopment.psd1
index af8c7bb..630f8e0 100644
--- a/PSModuleDevelopment/PSModuleDevelopment.psd1
+++ b/PSModuleDevelopment/PSModuleDevelopment.psd1
@@ -4,7 +4,7 @@
RootModule = 'PSModuleDevelopment.psm1'
# Version number of this module.
- ModuleVersion = '2.2.9.107'
+ ModuleVersion = '2.2.10.120'
# ID used to uniquely identify this module
GUID = '37dd5fce-e7b5-4d57-ac37-832055ce49d6'
@@ -27,7 +27,7 @@
# Modules that must be imported into the global environment prior to importing
# this module
RequiredModules = @(
- @{ ModuleName = 'PSFramework'; ModuleVersion = '1.4.149' }
+ @{ ModuleName = 'PSFramework'; ModuleVersion = '1.6.198' }
@{ ModuleName = 'string'; ModuleVersion = '0.6.1' }
)
@@ -50,45 +50,57 @@
# Functions to export from this module
FunctionsToExport = @(
- 'Convert-PSMDMessage',
- 'Expand-PSMDTypeName',
- 'Export-PSMDString',
- 'Find-PSMDFileContent',
- 'Find-PSMDType',
- 'Format-PSMDParameter',
- 'Get-PSMDArgumentCompleter',
- 'Get-PSMDAssembly',
- 'Get-PSMDConstructor',
- 'Get-PSMDFileCommand',
- 'Get-PSMDHelp',
- 'Get-PSMDMember',
- 'Get-PSMDModuleDebug',
- 'Get-PSMDTemplate',
- 'Import-PSMDModuleDebug',
- 'Invoke-PSMDTemplate',
- 'Measure-PSMDCommand',
- 'Measure-PSMDLinesOfCode',
- 'New-PSMDDotNetProject',
- 'New-PSMDHeader',
- 'New-PSMDFormatTableDefinition',
- 'New-PSMDModuleNugetPackage',
- 'New-PSMDTemplate',
- 'New-PssModuleProject',
- 'Publish-PSMDScriptFile',
- 'Publish-PSMDStagedModule',
- 'Read-PSMDScript',
- 'Remove-PSMDModuleDebug',
- 'Remove-PSMDTemplate',
- 'Rename-PSMDParameter',
- 'Restart-PSMDShell',
- 'Search-PSMDPropertyValue',
- 'Set-PSMDEncoding',
- 'Set-PSMDModuleDebug',
- 'Set-PSMDCmdletBinding',
- 'Set-PSMDModulePath',
- 'Set-PSMDParameterHelp',
- 'Set-PSMDStagingRepository',
- 'Show-PSMDSyntax',
+ 'Convert-PSMDMessage'
+ 'Expand-PSMDTypeName'
+ 'Export-PSMDString'
+ 'Find-PSMDFileContent'
+ 'Find-PSMDType'
+ 'Format-PSMDParameter'
+ 'Get-PSMDArgumentCompleter'
+ 'Get-PSMDAssembly'
+ 'Get-PSMDBuildAction'
+ 'Get-PSMDBuildArtifact'
+ 'Get-PSMDBuildProject'
+ 'Get-PSMDBuildStep'
+ 'Get-PSMDConstructor'
+ 'Get-PSMDFileCommand'
+ 'Get-PSMDHelp'
+ 'Get-PSMDMember'
+ 'Get-PSMDModuleDebug'
+ 'Get-PSMDTemplate'
+ 'Import-PSMDModuleDebug'
+ 'Invoke-PSMDBuildProject'
+ 'Invoke-PSMDTemplate'
+ 'Measure-PSMDCommand'
+ 'Measure-PSMDLinesOfCode'
+ 'New-PSMDBuildProject'
+ 'New-PSMDDotNetProject'
+ 'New-PSMDFormatTableDefinition'
+ 'New-PSMDHeader'
+ 'New-PSMDModuleNugetPackage'
+ 'New-PSMDTemplate'
+ 'New-PssModuleProject'
+ 'Publish-PSMDBuildArtifact'
+ 'Publish-PSMDScriptFile'
+ 'Publish-PSMDStagedModule'
+ 'Read-PSMDScript'
+ 'Register-PSMDBuildAction'
+ 'Remove-PSMDBuildArtifact'
+ 'Remove-PSMDModuleDebug'
+ 'Remove-PSMDTemplate'
+ 'Rename-PSMDParameter'
+ 'Resolve-PSMDBuildStepParameter'
+ 'Restart-PSMDShell'
+ 'Search-PSMDPropertyValue'
+ 'Select-PSMDBuildProject'
+ 'Set-PSMDBuildStep'
+ 'Set-PSMDCmdletBinding'
+ 'Set-PSMDEncoding'
+ 'Set-PSMDModuleDebug'
+ 'Set-PSMDModulePath'
+ 'Set-PSMDParameterHelp'
+ 'Set-PSMDStagingRepository'
+ 'Show-PSMDSyntax'
'Split-PSMDScriptFile'
)
@@ -99,15 +111,16 @@
# VariablesToExport = ''
# Aliases to export from this module
- AliasesToExport = @(
- 'dotnetnew',
- 'find',
- 'hex',
- 'imt',
- 'ipmod',
- 'parse',
- 'Restart-Shell',
- 'rss',
+ AliasesToExport = @(
+ 'build'
+ 'dotnetnew'
+ 'find'
+ 'hex'
+ 'imt'
+ 'ipmod'
+ 'parse'
+ 'Restart-Shell'
+ 'rss'
'smd'
)
diff --git a/PSModuleDevelopment/bin/PSModuleDevelopment.dll b/PSModuleDevelopment/bin/PSModuleDevelopment.dll
index 4e23017..4d4a049 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 e84f1e7..68f03cb 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 2f778e5..cc60b59 100644
--- a/PSModuleDevelopment/bin/PSModuleDevelopment.xml
+++ b/PSModuleDevelopment/bin/PSModuleDevelopment.xml
@@ -282,6 +282,141 @@
The constructor info object describing the constructor
+
+
+ Base class for all kinds of parameters gen 2+
+
+
+
+
+ Name of the parameter
+
+
+
+
+ Description of the parameter
+
+
+
+
+ Get the value associated with this parameter
+
+ The value to insert into the artifact generated from the template
+
+
+
+ A template parameter where the user is prompted for input.
+
+
+
+
+ The value provided by the user
+
+
+
+
+ List of legal values to provide
+
+
+
+
+ A validation pattern that needs to be met.
+
+
+
+
+ An error description that will be shown if the user provides invalid input to a parameter with pattern validation.
+
+
+
+
+ Test whether the input meets the validation rules
+
+ The value to test
+ Whether the value is valid.
+
+
+
+ Return the value specified by the user.
+
+ The value specified by the user
+
+
+
+ Parameter type executing
+
+
+
+
+ The scriptblock to execute.
+ Wrapped as string for serialization purposes.
+
+
+
+
+ The value of the scriptblock.
+ Populated by the GetValue() method usually called with the "StartUp" timing.
+
+
+
+
+ When exactly during the template process should this scriptblock be executed?
+
+
+
+
+ Setting this to true will cause the Invoke-PSMDTemplate command to omit inserting values for the
+
+
+
+
+ Returns the string value of the scriptblock by executing it!
+
+ The string value of the scriptblock by executing it!
+
+
+
+ Execute the scriptblock "Just-in-time" during either PreItemCreation or PostItemCreation Timing.
+
+ The file/directory info object of the object recently or about to be created
+ Returns a string value resulting from the scriptblock to insert
+
+
+
+ Execute the scriptblock "Just-in-time" during either PreItemCreation or PostItemCreation Timing.
+
+ The path to the file/directory info object of the object recently or about to be created
+ Whether the object (about to be) created is a file.
+ Returns a string value resulting from the scriptblock to insert
+
+
+
+ When will a specific scriptblock parameter be executed?
+
+
+
+
+ Executed when starting the overall template invocation
+
+
+
+
+ Executed before an individual item using it is created.
+ Values will be inserted into the file-content before writing to disk if applicable.
+
+
+
+
+ Executed after the individual item using it has been created.
+ Output will be discarded, but scriptblock will receive path of file / folder.
+
+
+
+
+ Executed after the entire project has been written.
+ Enables post-processing.
+
+
A script used to calculate content to be inserted
@@ -395,11 +530,21 @@
List of scripts that will be invoked on initialization
+
+
+ List of generation 2 parameters to include
+
+
Items in the root directory of the template (which may contain children themselves).
+
+
+ What design generation is the template?
+
+
Returns the template digest used as index file.
@@ -461,6 +606,11 @@
The path to the template file
+
+
+ What template generation is this file?
+
+
The version-qualified name of the template
diff --git a/PSModuleDevelopment/changelog.md b/PSModuleDevelopment/changelog.md
index da0083f..c55f4fa 100644
--- a/PSModuleDevelopment/changelog.md
+++ b/PSModuleDevelopment/changelog.md
@@ -1,11 +1,27 @@
# Changelog
+## 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)
+
## 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
-- Fix: Publish-PSMDScriptFile - insufficient exclude paths (#138; @Callidus2000)
## 2.2.8.104 (July 26th, 2020)
diff --git a/PSModuleDevelopment/en-us/strings.psd1 b/PSModuleDevelopment/en-us/strings.psd1
index 65c294e..e8c66ff 100644
--- a/PSModuleDevelopment/en-us/strings.psd1
+++ b/PSModuleDevelopment/en-us/strings.psd1
@@ -4,6 +4,11 @@
'Get-PSMDFileCommand.SyntaxError' = 'Syntax error in file: {0}' # $pathItem
+ 'Invoke-PSMDBuildProject.Step.Executing' = '[{0}] Executing step {1} ({2})' # $count, $step.Name, $step.Action
+
+ 'Invoke-PSMDTemplate.Template.NotFound' = 'Unable to find template data for "{0}"' # $TemplateName
+ 'Invoke-PSMDTemplate.Invoking' = 'Creating file/project from template {0}' # $item
+
'MeasurePSMDLinesOfCode.Processing' = 'Processing Path: {0}' # $fileItem
'Publish-PSMDScriptFile.Module.Saving' = 'Saving module {0} from repository {1}' # $moduleName, (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Script.StagingRepository')
diff --git a/PSModuleDevelopment/functions/build/Get-PSMDBuildAction.ps1 b/PSModuleDevelopment/functions/build/Get-PSMDBuildAction.ps1
new file mode 100644
index 0000000..6ff5b48
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Get-PSMDBuildAction.ps1
@@ -0,0 +1,29 @@
+function Get-PSMDBuildAction {
+<#
+ .SYNOPSIS
+ Get a list of registered build actions.
+
+ .DESCRIPTION
+ Get a list of registered build actions.
+ Actions are the scriptblocks that are used to execute the build logic when running Invoke-PSMDBuildProject.
+
+ .PARAMETER Name
+ The name by which to filter the actions returned.
+ Defaults to '*'
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildAction
+
+ Get a list of all registered build actions.
+#>
+ [CmdletBinding()]
+ param (
+ [PsfArgumentCompleter('PSModuleDevelopment.Build.Action')]
+ [string]
+ $Name = '*'
+ )
+
+ process {
+ $script:buildActions.Values | Where-Object Name -Like $Name
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Get-PSMDBuildArtifact.ps1 b/PSModuleDevelopment/functions/build/Get-PSMDBuildArtifact.ps1
new file mode 100644
index 0000000..011accc
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Get-PSMDBuildArtifact.ps1
@@ -0,0 +1,54 @@
+function Get-PSMDBuildArtifact {
+<#
+ .SYNOPSIS
+ Retrieve an artifact during a build project's execution.
+
+ .DESCRIPTION
+ Retrieve an artifact during a build project's execution.
+ These artifacts are usually created during such an execution and discarded once completed.
+
+ .PARAMETER Name
+ The name by which to search for artifacts.
+ Defaults to '*'
+
+ .PARAMETER Tag
+ Search for artifacts by tag.
+ Artifacts can receive tag for better categorization.
+ When specifying multiple tags, any artifact containing at least one of them will be returned.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildArtifact
+
+ List all available artifacts.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildArtifact -Name ReleasePath
+
+ Returns the artifact named "ReleasePath"
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildArtifact -Tag pssession
+
+ Returns all artifacts with the tag "pssession"
+#>
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
+ [CmdletBinding()]
+ param (
+ [string]
+ $Name = '*',
+
+ [string[]]
+ $Tag
+ )
+
+ process {
+ $artifacts = $script:buildArtifacts.Values | Where-Object Name -Like $Name | Where-Object {
+ if (-not $Tag) { return $true }
+ foreach ($tagName in $Tag) {
+ if ($_.Tags -contains $Tag) { return $true }
+ }
+ return $false
+ }
+ $($artifacts)
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Get-PSMDBuildProject.ps1 b/PSModuleDevelopment/functions/build/Get-PSMDBuildProject.ps1
new file mode 100644
index 0000000..93a7594
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Get-PSMDBuildProject.ps1
@@ -0,0 +1,60 @@
+function Get-PSMDBuildProject {
+<#
+ .SYNOPSIS
+ Reads & returns a build project.
+
+ .DESCRIPTION
+ Reads & returns a build project.
+ A build project is a container including the steps executed during the build.
+
+ .PARAMETER Path
+ Path to the build project file.
+ May target the folder, in which case the -Name parameter must be specified.
+
+ .PARAMETER Name
+ The name of the build project to read.
+ Use together with the -Path parameter only.
+ Absolute file path assumed will be: "\.build.json"
+
+ .PARAMETER Selected
+ Rather than specifying the path to read from, return the currently selected build project.
+ Use Select-PSMDBuildProject to select a build project as the default ("selected") project.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildProject -Path 'C:\code\project' -Name project
+
+ Will load the build project stored in the file "C:\code\project\project.build.json"
+#>
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
+ [CmdletBinding(DefaultParameterSetName = 'Path')]
+ param (
+ [Parameter(Mandatory = $true, ParameterSetName = 'Path')]
+ [string]
+ $Path,
+
+ [Parameter(ParameterSetName = 'Path')]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory = $true, ParameterSetName = 'Selected')]
+ [switch]
+ $Selected
+ )
+
+ process {
+ #region By Path
+ if ($Path) {
+ $importPath = $Path
+ if ($Name) { $importPath = Join-Path -Path $Path -ChildPath "$Name.build.json" }
+
+ Get-Content -Path $importPath -Encoding UTF8 | ConvertFrom-Json
+ }
+ #endregion By Path
+
+ #region Selected
+ else {
+ Get-Content -Path (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Build.Project.Selected') -Encoding UTF8 | ConvertFrom-Json
+ }
+ #endregion Selected
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Get-PSMDBuildStep.ps1 b/PSModuleDevelopment/functions/build/Get-PSMDBuildStep.ps1
new file mode 100644
index 0000000..7c9890e
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Get-PSMDBuildStep.ps1
@@ -0,0 +1,49 @@
+function Get-PSMDBuildStep {
+<#
+ .SYNOPSIS
+ Read the steps that are part of the specified build project.
+
+ .DESCRIPTION
+ Read the steps that are part of the specified build project.
+
+ .PARAMETER Name
+ The name by which to filter the steps returned.
+ Defaults to '*'
+
+ .PARAMETER BuildProject
+ Path to the build project file to read from.
+ Defaults to the currently selected project if available.
+ Use Select-PSMDBuildProject to select a default project.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildStep
+
+ Read all steps that are part of the default build project.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildStep -Name CreateSession -BuildProject C:\code\Project\Project.build.json
+
+ Return the CreateSession step from the specified project file.
+#>
+ [CmdletBinding()]
+ param (
+ [string]
+ $Name = '*',
+
+ [string]
+ $BuildProject
+ )
+
+ begin {
+ $projectPath = $BuildProject
+ if (-not $projectPath) { $projectPath = Get-PSFConfigValue -FullName 'PSModuleDevelopment.Build.Project.Selected' }
+ if (-not $projectPath) { throw "No Project path specified and none selected!" }
+ if (-not (Test-Path -Path $projectPath)) {
+ throw "Project file not found: $projectPath"
+ }
+ }
+ process {
+ $projectObject = Get-PSMDBuildProject -Path $projectPath
+ $projectObject.Steps | Where-Object Name -Like $Name
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Invoke-PSMDBuildProject.ps1 b/PSModuleDevelopment/functions/build/Invoke-PSMDBuildProject.ps1
new file mode 100644
index 0000000..ee8567b
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Invoke-PSMDBuildProject.ps1
@@ -0,0 +1,175 @@
+function Invoke-PSMDBuildProject {
+<#
+ .SYNOPSIS
+ Execute a build project.
+
+ .DESCRIPTION
+ Execute a build project.
+ A build project is a configured chain of actions that have been configured in json.
+ They will be processed in their specified order and allow manageable, configurable steps without having to reinvent the same action again and again.
+
+ + Individual action types become available using Register-PSMDBuildAction.
+ + Create new build projects using New-PSMDBuildProject
+ + Set up steps taken during a build using Set-PSMDBuildStep
+ + Select the default build project using Select-PSMDBuildProject
+
+ .PARAMETER Path
+ The path to the build project file to execute.
+ Mandatory if no build project has been selected as the default project.
+ Use the Select-PSMDBuildProject to define a default project (and optionally persist the choice across sessions)
+
+ .PARAMETER RetainArtifacts
+ Whether, after executing the project, its artifacts should be retained.
+ By default, any artifacts created during a build project will be discarded upon project completion.
+
+ Artifacts are similar to variables to the pipeline and can be used to pass data throughout the pipeline.
+
+ + Use Publish-PSMDBuildArtifact to create a new artifact.
+ + Use Get-PSMDBuildArtifact to access existing build artifacts.
+
+ .EXAMPLE
+ PS C:\> Invoke-PSMDBuildProject -Path .\VMDeployment.build.Json
+
+ Execute the build file "VMDeployment.build.json" from the current folder
+
+ .EXAMPLE
+ PS C:\> build
+
+ Execute the default build project.
+#>
+ [Alias('build')]
+ [CmdletBinding()]
+ param (
+ [string]
+ $Path,
+
+ [switch]
+ $RetainArtifacts
+ )
+
+ begin {
+ $script:buildArtifacts = @{ }
+ $buildStatus = @{ }
+
+ $projectPath = $Path
+ if (-not $projectPath) { $projectPath = Get-PSFConfigValue -FullName 'PSModuleDevelopment.Build.Project.Selected' }
+ if (-not $projectPath) { throw "No Project path specified and none selected!" }
+ if (-not (Test-Path -Path $projectPath)) {
+ throw "Project file not found: $projectPath"
+ }
+
+ function Write-StepResult {
+ [CmdletBinding()]
+ param (
+ [int]
+ $Count,
+
+ [ValidateSet('Success', 'Failed', 'ConditionNotMet', 'DependencyNotMet', 'BadAction')]
+ [string]
+ $Status,
+
+ $StepObject,
+
+ $Data,
+
+ [hashtable]
+ $BuildStatus,
+
+ [string]
+ $ContinueLabel
+ )
+
+ $BuildStatus[$StepObject.Name] = $Status -eq 'Success'
+
+ $paramWritePSFMessage = @{
+ Level = 'Warning'
+ String = "Invoke-PSMDBuildProject.Step.$Status"
+ }
+
+ switch ($Status) {
+ Failed { Write-PSFMessage @paramWritePSFMessage -StringValues $StepObject.Name, $StepObject.Action -ErrorRecord $Data }
+ ConditionNotMet { Write-PSFMessage @paramWritePSFMessage -StringValues $StepObject.Name, $StepObject.Action, $StepObject.Condition }
+ DependencyNotMet { Write-PSFMessage @paramWritePSFMessage -StringValues $StepObject.Name, $StepObject.Action, $Data }
+ BadAction { Write-PSFMessage @paramWritePSFMessage -StringValues $StepObject.Name, $StepObject.Action }
+ }
+
+ [PSCustomObject]@{
+ PSTypeName = 'PSModuleDevelopment.Build.StepResult'
+ Count = $Count
+ Action = $StepObject.Action
+ Status = $Status
+ Step = $StepObject.Name
+ Data = $Data
+ }
+
+ if ($ContinueLabel) {
+ continue $ContinueLabel
+ }
+ }
+ }
+ process {
+ $projectObject = Get-PSMDBuildProject -Path $projectPath
+ $steps = $projectObject.Steps | Sort-Object Weight
+
+ $count = 0
+ $stepResults = :main foreach ($step in $steps) {
+ $count++
+ $resultDef = @{
+ Count = $count
+ StepObject = $step
+ BuildStatus = $buildStatus
+ }
+
+ Write-PSFMessage -Level Host -String 'Invoke-PSMDBuildProject.Step.Executing' -StringValues $count, $step.Name, $step.Action
+
+ #region Validation
+ $actionObject = $script:buildActions[$step.Action]
+ if (-not $actionObject) {
+ Write-StepResult @resultDef -Status BadAction -ContinueLabel main
+ }
+
+ foreach ($dependency in $step.Dependency) {
+ if (-not $buildStatus[$dependency]) {
+ Write-StepResult @resultDef -Status DependencyNotMet -Data $dependency -ContinueLabel main
+ }
+ }
+
+ if ($step.Condition -and $step.ConditionSet) {
+ $cModule, $cSetName = $step.ConditionSet -split " ", 2
+ $conditionSet = Get-PSFFilterConditionSet -Module $cModule -Name $cSetName
+ if (-not $conditionSet) {
+ Write-StepResult @resultDef -Status ConditionNotMet -ContinueLabel main
+ }
+
+ $filter = New-PSFFilter -Expression $step.Condition -ConditionSet $conditionSet
+ if (-not $filter.Evaluate()) {
+ Write-StepResult @resultDef -Status ConditionNotMet -ContinueLabel main
+ }
+ }
+ #endregion Validation
+
+ #region Execution
+ $parameters = @{
+ RootPath = Split-Path -Path $projectPath
+ Parameters = $step.Parameters | ConvertTo-PSFHashtable
+ ProjectName = $projectObject.Name
+ StepName = $step.Name
+ ParametersFromArtifacts = $step.ParametersFromArtifacts | ConvertTo-PSFHashtable
+ }
+ if (-not $parameters.Parameters) { $parameters.Parameters = @{ } }
+ if (-not $parameters.ParametersFromArtifacts) { $parameters.ParametersFromArtifacts = @{ } }
+ try { $null = & $actionObject.Action $parameters }
+ catch {
+ Write-StepResult @resultDef -Status Failed -Data $_ -ContinueLabel main
+ }
+ Write-StepResult @resultDef -Status Success
+ #endregion Execution
+ }
+ $stepResults
+ }
+ end {
+ if (-not $RetainArtifacts) {
+ $script:buildArtifacts = @{ }
+ }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/New-PSMDBuildProject.ps1 b/PSModuleDevelopment/functions/build/New-PSMDBuildProject.ps1
new file mode 100644
index 0000000..6d44498
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/New-PSMDBuildProject.ps1
@@ -0,0 +1,94 @@
+function New-PSMDBuildProject {
+<#
+ .SYNOPSIS
+ Create a new build project file.
+
+ .DESCRIPTION
+ Create a new build project file.
+ Build projects are used to configure a repeatable, managed set of steps that make up a workflow.
+ It is designed with software build processes in mind, but can be used for pretty much anything that works in separate steps.
+
+ See the help on Invoke-PSMDBuildProject for more details.
+
+ NOTE: This is not the tool or component to create new PowerShell _code_ projects / repositories!
+ To create a new PowerShell module project, instead run:
+
+ Invoke-PSMDTemplate PSFProject
+
+ .PARAMETER Name
+ The name of the build project.
+
+ .PARAMETER Path
+ The path to the folder in which the build project file is created.
+ Final path will be: "\.build.json"
+
+ .PARAMETER Condition
+ A condition - a filter expression - that must be met in order for the build to proceed.
+ For more details on filter conditions, see the PSFramework documentation on its feature:
+ https://psframework.org/documentation/documents/psframework/filters.html
+
+ .PARAMETER ConditionSet
+ The name of the condition set to use.
+ This is part of the PSFramework filter system:
+ https://psframework.org/documentation/documents/psframework/filters.html
+
+ Specify as " " format.
+ Default Value: PSFramework Environment
+
+ .PARAMETER NoSelect
+ Do not select the newly created build project as the default project for the current session.
+ By default, the newly created build project will be set as default project, in order to facilitate adding steps to it.
+ Use Select-PSMDBuildProject to explicitly set a default project file.
+
+ .PARAMETER Register
+ Persist the newly created build project as default build project beyond the current session.
+ By default, the newly created build project will already be set as default project, in order to facilitate adding steps to it.
+ But ONLY for the current session. This parameter makes it remember in new PowerShell sessions as well.
+
+ .EXAMPLE
+ PS C:\> New-PSMDBuildProject -Name 'VMDeployment' -Path 'C:\Code\VMDeployment'
+
+ Create a new build project named 'VMDeployment' in the folder 'C:\Code\VMDeployment'
+#>
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
+ [CmdletBinding(DefaultParameterSetName = 'default')]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory = $true)]
+ [PsfValidateScript('PSFramework.Validate.FSPath.Folder', ErrorString = 'PSFramework.Validate.FSPath.Folder')]
+ [string]
+ $Path,
+
+ [string]
+ $Condition,
+
+ [string]
+ $ConditionSet = 'PSFramework Environment',
+
+ [Parameter(ParameterSetName = 'NoSelect')]
+ [switch]
+ $NoSelect,
+
+ [Parameter(ParameterSetName = 'Register')]
+ [switch]
+ $Register
+ )
+
+ process {
+ $project = [pscustomobject]@{
+ Name = $Name
+ Condition = $Condition
+ ConditionSet = $ConditionSet
+ Steps = @()
+ }
+ $outPath = Join-Path -Path $Path -ChildPath "$Name.build.Json"
+ $project | Export-PsmdBuildProjectFile -OutPath $outPath -ErrorAction Stop
+ if (-not $NoSelect) {
+ Set-PSFConfig -Module PSModuleDevelopment -Name 'Build.Project.Selected' -Value $outPath
+ if ($Register) { Register-PSFConfig -Module PSModuleDevelopment -Name 'Build.Project.Selected' }
+ }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Publish-PSMDBuildArtifact.ps1 b/PSModuleDevelopment/functions/build/Publish-PSMDBuildArtifact.ps1
new file mode 100644
index 0000000..6223327
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Publish-PSMDBuildArtifact.ps1
@@ -0,0 +1,54 @@
+function Publish-PSMDBuildArtifact {
+<#
+ .SYNOPSIS
+ Create a new artifact for the current build pipeline.
+
+ .DESCRIPTION
+ Create a new artifact for the current build pipeline.
+ Use this create artifacts that are accessible in later steps in the pipeline.
+
+ Usually, artifacts are deleted at the end of a build process.
+ They are always cleared at the beginning of a new one.
+
+ Artifacts are NOT persisted across PowerShell sessions.
+
+ .PARAMETER Name
+ Name of the Artifact to create.
+ Technically there are no limits to which character to chose, but we strongly encourage restricting yourself to letters, numbers, dash, underscore and dot.
+
+ .PARAMETER Value
+ The value to assign to the artifact.
+
+ .PARAMETER Tag
+ Any tags to add to an artifact.
+ Tags can be searched for in order to bulk-operate against all artifacts of that tag.
+ For example, the "remove-pssession" action can remove all remoting sessions for all artifacts tagged as "pssession".
+
+ .EXAMPLE
+ PS C:\> Publish-PSMDBuildArtifact -Name 'session' -Value $session -Tag 'pssession'
+
+ Publishes an artifact named "session" containing the content of $session that is tagged as a PowerShell remoting session.
+#>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory = $true)]
+ [AllowNull()]
+ $Value,
+
+ [string[]]
+ $Tag = @()
+ )
+
+ process {
+ $script:buildArtifacts[$Name] = [pscustomobject]@{
+ PSTypeName = 'PSModuleDevelopment.Build.Artifact'
+ Name = $Name
+ Value = $Value
+ Tags = $Tag
+ }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Register-PSMDBuildAction.ps1 b/PSModuleDevelopment/functions/build/Register-PSMDBuildAction.ps1
new file mode 100644
index 0000000..8728f03
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Register-PSMDBuildAction.ps1
@@ -0,0 +1,62 @@
+function Register-PSMDBuildAction {
+<#
+ .SYNOPSIS
+ Register a new action usable in build projects.
+
+ .DESCRIPTION
+ Register a new action usable in build projects.
+ Actions are the actual implementation logic that turns the configuration in a build project file into ... well, actions.
+ Anyway, these are basically named scriptblocks with some metadata.
+ This command is used to provide all the builtin actions and can be used to freely define your own actions.
+
+ Whenever you use a "script" action in your build projects, consider ... would it make a good configurable option valuable for other builds?
+ If so, that might just mark the birth of the next action!
+
+ .PARAMETER Name
+ The name of the action.
+
+ .PARAMETER Action
+ The actual code implementing the action.
+ Each action scriptblock will receive exactly one .
+
+ .PARAMETER Description
+ A description explaining what the action is all about.
+
+ .PARAMETER Parameters
+ The parameters the action accepts.
+ Provider a hashtable, with the keys being the parameter names and the values being a description of its parameter.
+
+ .EXAMPLE
+ PS C:\> Register-PSMDBuildAction -Name 'script' -Action $actionCode -Description 'Execute a custom scriptfile as part of your workflow' -Parameters $parameters
+
+ Creates / registers the action "script".
+#>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Name,
+
+ [Parameter(Mandatory = $true)]
+ [ScriptBlock]
+ $Action,
+
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Description,
+
+ [Parameter(Mandatory = $true)]
+ [hashtable]
+ $Parameters
+ )
+
+ process {
+ $script:buildActions[$Name] = [pscustomobject]@{
+ PSTypeName = 'PSModuleDevelopment.Build.Action'
+ Name = $Name
+ Action = $Action
+ Description = $Description
+ Parameters = $Parameters
+ }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Remove-PSMDBuildArtifact.ps1 b/PSModuleDevelopment/functions/build/Remove-PSMDBuildArtifact.ps1
new file mode 100644
index 0000000..a6c354b
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Remove-PSMDBuildArtifact.ps1
@@ -0,0 +1,37 @@
+function Remove-PSMDBuildArtifact
+{
+<#
+ .SYNOPSIS
+ Removes an artifact from the build pipeline.
+
+ .DESCRIPTION
+ Removes an artifact from the build pipeline.
+ Only interacts with the PSModuleDevelopment build system.
+
+ .PARAMETER Name
+ Name of the artifact to remove.
+
+ .EXAMPLE
+ PS C:\> Remove-PSMDBuildArtifact -Name 'session'
+
+ Removes the artifact 'session' from the build pipeline.
+
+ .EXAMPLE
+ PS C:\> Get-PSMDBuildArtifact -Tag pssession | Remove-PSMDBuildArtifact
+
+ Removes all artifacts with the 'pssession' tag from the build pipeline.
+#>
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
+ [string[]]
+ $Name
+ )
+
+ process{
+ foreach ($nameString in $Name) {
+ $script:buildArtifacts.Remove($nameString)
+ }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Resolve-PSMDBuildStepParameter.ps1 b/PSModuleDevelopment/functions/build/Resolve-PSMDBuildStepParameter.ps1
new file mode 100644
index 0000000..82c7ffc
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Resolve-PSMDBuildStepParameter.ps1
@@ -0,0 +1,69 @@
+function Resolve-PSMDBuildStepParameter {
+<#
+ .SYNOPSIS
+ Update missing build action parameters from the configuration system.
+
+ .DESCRIPTION
+ Update missing build action parameters from the configuration system.
+ This command is for use within the defined code of build actions.
+
+ .PARAMETER Parameters
+ The hashtable containing the currently specified parameters from the step configuration within the build project file.
+ Only settings not already defined there are taken from configuration.
+
+ .PARAMETER FromArtifacts
+ The hashtable mapping parameters from artifacts.
+ This allows dynamically assigning artifacts to parameters.
+
+ .PARAMETER ProjectName
+ The name of the project being executed.
+ Supplementary parameters taken from configuration will pick up settings based on this name:
+ "PSModuleDevelopment.BuildParam...*"
+
+ .PARAMETER StepName
+ The name of the step being executed.
+ Supplementary parameters taken from configuration will pick up settings based on this name:
+ "PSModuleDevelopment.BuildParam...*"
+
+ .EXAMPLE
+ PS C:\> Resolve-PSMDBuildStepParameter -Parameters $actualParameters -ProjectName VMDeployment -StepName 'Create Session'
+
+ Adds parameters provided through configuration.
+#>
+ [OutputType([hashtable])]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [hashtable]
+ $Parameters,
+
+ [Parameter(Mandatory = $true)]
+ [hashtable]
+ $FromArtifacts,
+
+ [Parameter(Mandatory = $true)]
+ [string]
+ $ProjectName,
+
+ [Parameter(Mandatory = $true)]
+ [string]
+ $StepName
+ )
+
+ process {
+ # Process parameters from Configuration
+ $configObject = Select-PSFConfig -FullName "PSModuleDevelopment.BuildParam.$ProjectName.$StepName.*"
+ foreach ($property in $configObject.PSObject.Properties) {
+ if ($property.Name -in '_Name', '_FullName', '_Depth', '_Children') { continue }
+ if ($Parameters.ContainsKey($property.Name)) { continue }
+ $Parameters[$property.Name] = $property.Value
+ }
+
+ # Process parameters from Artifacts
+ foreach ($pair in $FromArtifacts.GetEnumerator()) {
+ $Parameters[$pair.Key] = (Get-PSMDBuildArtifact -Name $pair.Value).Value
+ }
+
+ $Parameters
+ }
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/build/Select-PSMDBuildProject.ps1 b/PSModuleDevelopment/functions/build/Select-PSMDBuildProject.ps1
new file mode 100644
index 0000000..b915741
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Select-PSMDBuildProject.ps1
@@ -0,0 +1,40 @@
+function Select-PSMDBuildProject
+{
+<#
+ .SYNOPSIS
+ Set the specified build project as the default project.
+
+ .DESCRIPTION
+ Set the specified build project as the default project.
+ This will have most other commands in this Component automatically use the specified project.
+
+ .PARAMETER Path
+ Path to the project file to pick.
+
+ .PARAMETER Register
+ Persist the choice as default build project file across PowerShell sessions.
+
+ .EXAMPLE
+ PS C:\> Select-PSMDBuildProject -Path 'c:\code\Project\Project.build.json'
+
+ Sets the specified build project as the default project.
+#>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Path,
+
+ [switch]
+ $Register
+ )
+
+ process
+ {
+ Invoke-PSFProtectedCommand -ActionString 'Select-PSMDBuildProject.Testing' -ActionStringValues $Path -ScriptBlock {
+ $null = Get-PSMDBuildProject -Path $Path -ErrorAction Stop
+ } -Target $Path -EnableException $true -PSCmdlet $PSCmdlet
+ Set-PSFConfig -Module PSModuleDevelopment -Name 'Build.Project.Selected' -Value $Path
+ if ($Register) { Register-PSFConfig -Module PSModuleDevelopment -Name 'Build.Project.Selected' }
+ }
+}
diff --git a/PSModuleDevelopment/functions/build/Set-PSMDBuildStep.ps1 b/PSModuleDevelopment/functions/build/Set-PSMDBuildStep.ps1
new file mode 100644
index 0000000..07b3722
--- /dev/null
+++ b/PSModuleDevelopment/functions/build/Set-PSMDBuildStep.ps1
@@ -0,0 +1,120 @@
+function Set-PSMDBuildStep {
+<#
+ .SYNOPSIS
+ Create or update a step from a build project.
+
+ .DESCRIPTION
+ Create or update a step from a build project.
+
+ .PARAMETER Name
+ The name of the step.
+ All step names must be unique within a single build project.
+
+ .PARAMETER Weight
+ The weight of the step.
+ Weight determines processing order, the lower the number the earlier it is executed.
+
+ .PARAMETER Action
+ The name of the action to execute.
+ Use Get-PSMDBuildAction to get a list of available actions.
+
+ .PARAMETER Parameters
+ The parameters this action should take.
+ See the action object to see a description of parameters, including which must be provided and which can be skipped.
+
+ .PARAMETER Condition
+ A PSFramework filter condition that must apply for this action to be executed successfully.
+ Example Conditions:
+ Elevated
+ PS7Plus -and OSWindows
+ More Details: https://psframework.org/documentation/documents/psframework/filters.html
+
+ .PARAMETER ConditionSet
+ The name of the condition set to use.
+ This is part of the PSFramework filter system:
+ https://psframework.org/documentation/documents/psframework/filters.html
+
+ Specify as " " format.
+ Default Value: PSFramework Environment
+
+ .PARAMETER Dependency
+ Any other steps that must successfully finished in order for this step to execute.
+ ALL of the listed steps must have succeeded, skipped steps do not count.
+
+ .PARAMETER BuildProject
+ The build project file to work against.
+ Specify the full path to the build project file.
+ This parameter can be skipped if a default project file has been defined.
+
+ .EXAMPLE
+ PS C:\> Set-PSMDBuildStep -Name 'Create Session' -Action new-pssession -Parameters @{ VMName = 'labdc1'; CredentialPath = "%ProjectRoot%\creds\labdc1.cred"; }
+
+ Defines a new step named 'Create Session' using the 'new-pssession'-action.
+#>
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $Name,
+
+ [int]
+ $Weight,
+
+ [PsfArgumentCompleter('PSModuleDevelopment.Build.Action')]
+ [string]
+ $Action,
+
+ [hashtable]
+ $Parameters,
+
+ [string]
+ $Condition,
+
+ [string]
+ $ConditionSet,
+
+ [string[]]
+ $Dependency,
+
+ [string]
+ $BuildProject
+ )
+
+ begin {
+ $projectPath = $BuildProject
+ if (-not $projectPath) { $projectPath = Get-PSFConfigValue -FullName 'PSModuleDevelopment.Build.Project.Selected' }
+ if (-not $projectPath) { throw "No Project path specified and none selected!" }
+ if (-not (Test-Path -Path $projectPath)) {
+ throw "Project file not found: $projectPath"
+ }
+ }
+ process {
+ $projectObject = Get-PSMDBuildProject -Path $projectPath | ConvertTo-PSFHashtable
+ $stepObject = $projectObject.Steps | Where-Object Name -EQ $Name | ConvertTo-PSFHashtable
+ if (-not $stepObject) {
+ $stepObject = [pscustomobject]@{
+ PSTypeName = 'PSModuleDevelopment.Build.Step'
+ Name = $Name
+ Weight = 50
+ Action = ''
+ Parameters = @{ }
+ Condition = ''
+ ConditionSet = 'PSFramework Environment'
+ Dependency = @()
+ }
+ }
+ if (Test-PSFParameterBinding -ParameterName Weight) { $stepObject.Weight = $Weight }
+ if (Test-PSFParameterBinding -ParameterName Action) { $stepObject.Action = $Action }
+ if (Test-PSFParameterBinding -ParameterName Parameters) { $stepObject.Parameters = $Parameters }
+ if (Test-PSFParameterBinding -ParameterName Condition) { $stepObject.Condition = $Condition }
+ if (Test-PSFParameterBinding -ParameterName ConditionSet) { $stepObject.ConditionSet = $ConditionSet }
+ if (Test-PSFParameterBinding -ParameterName Dependency) { $stepObject.Dependency = $Dependency }
+
+ if (-not $stepObject.Action) {
+ throw "Failed to save Build Step $Name : No Action defined!"
+ }
+ $projectObject.Steps = @($projectObject.Steps | Where-Object Name -ne $Name) + @($stepObject)
+ $projectObject | Export-PsmdBuildProjectFile -OutPath $projectPath -ErrorAction Stop
+ }
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/help/Get-PSMDHelp.ps1 b/PSModuleDevelopment/functions/help/Get-PSMDHelp.ps1
index 98b7a6f..fa6bc5d 100644
--- a/PSModuleDevelopment/functions/help/Get-PSMDHelp.ps1
+++ b/PSModuleDevelopment/functions/help/Get-PSMDHelp.ps1
@@ -113,12 +113,8 @@
PS C:\> Get-PSMDHelp Get-Help "en-us" -Detailed
Gets the detailed help text of Get-Help in English
-
- .NOTES
- Version 1.0.0.0
- Author: Friedrich Weinmann
- Created on: August 15th, 2016
#>
+ [Alias('hex')]
[CmdletBinding(DefaultParameterSetName = "AllUsersView")]
Param (
[Parameter(ParameterSetName = "Parameters", Mandatory = $true)]
@@ -209,5 +205,4 @@
try { $steppablePipeline.End() }
catch { throw }
}
-}
-New-Alias -Name hex -Value Get-PSMDHelp -Scope Global -Option AllScope
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/moduledebug/Import-PSMDModuleDebug.ps1 b/PSModuleDevelopment/functions/moduledebug/Import-PSMDModuleDebug.ps1
index 7eca92d..2800849 100644
--- a/PSModuleDevelopment/functions/moduledebug/Import-PSMDModuleDebug.ps1
+++ b/PSModuleDevelopment/functions/moduledebug/Import-PSMDModuleDebug.ps1
@@ -15,6 +15,7 @@
Imports the cPSNetwork module as it was configured to be imported using Set-ModuleDebug.
#>
+ [Alias('ipmod')]
[CmdletBinding()]
param (
[string]
@@ -40,5 +41,4 @@
[System.Management.Automation.ScriptBlock]::Create($____module.PostImportAction).Invoke()
}
}
-}
-New-Alias -Name ipmod -Value Import-ModuleDebug -Option AllScope -Scope Global
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/moduledebug/Set-PSMDModuleDebug.ps1 b/PSModuleDevelopment/functions/moduledebug/Set-PSMDModuleDebug.ps1
index a9a8e65..92ea656 100644
--- a/PSModuleDevelopment/functions/moduledebug/Set-PSMDModuleDebug.ps1
+++ b/PSModuleDevelopment/functions/moduledebug/Set-PSMDModuleDebug.ps1
@@ -65,6 +65,7 @@
Note: Using Write-Host is generally - but not always - bad practice
Note: Verbose output during module import is generally discouraged (doesn't apply to tests of course)
#>
+ [Alias('smd')]
[CmdletBinding(DefaultParameterSetName = "Name", SupportsShouldProcess = $true)]
Param (
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = "Name", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
@@ -176,5 +177,4 @@
}
#endregion Name
}
-}
-Set-Alias -Name smd -Value Set-PSMDModuleDebug -Option AllScope -Scope Global
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/refactor/Read-PSMDScript.ps1 b/PSModuleDevelopment/functions/refactor/Read-PSMDScript.ps1
index 88a7105..b7f9fde 100644
--- a/PSModuleDevelopment/functions/refactor/Read-PSMDScript.ps1
+++ b/PSModuleDevelopment/functions/refactor/Read-PSMDScript.ps1
@@ -24,6 +24,7 @@
Parses all script files in the current directory
#>
+ [Alias('parse')]
[CmdletBinding()]
param (
[Parameter(Position = 0, ParameterSetName = 'Script', Mandatory = $true)]
@@ -78,5 +79,4 @@
}
}
}
-}
-Set-Alias -Name parse -Value Read-PSMDScript
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1 b/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1
index 54e6168..00df036 100644
--- a/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1
+++ b/PSModuleDevelopment/functions/templating/Get-PSMDTemplate.ps1
@@ -84,8 +84,6 @@
begin
{
- Write-PSFMessage -Level InternalComment -Message "Bound parameters: $($PSBoundParameters.Keys -join ", ")" -Tag 'debug', 'start', 'param'
-
$prospects = @()
}
process
@@ -97,7 +95,7 @@
foreach ($info in $templateInfos)
{
- $data = Import-Clixml $info.FullName
+ $data = Import-PSFClixml $info.FullName
$data.Path = $info.FullName -replace '\.Info\.xml$','.xml'
$prospects += $data
}
@@ -117,7 +115,7 @@
foreach ($info in $templateInfos)
{
- $data = Import-Clixml $info.FullName
+ $data = Import-PSFClixml $info.FullName
$data.Path = $info.FullName -replace '-Info\.xml$', '.xml'
$data.Store = $item.Name
$prospects += $data
diff --git a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1 b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
index fea81e3..ce29e0c 100644
--- a/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
+++ b/PSModuleDevelopment/functions/templating/Invoke-PSMDTemplate.ps1
@@ -1,5 +1,4 @@
-function Invoke-PSMDTemplate
-{
+function Invoke-PSMDTemplate {
<#
.SYNOPSIS
Creates a project/file from a template.
@@ -79,6 +78,7 @@
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSPossibleIncorrectUsageOfAssignmentOperator", "")]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
+ [Alias('imt')]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
[Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'NameStore')]
@@ -99,6 +99,7 @@
$Path,
[Parameter(Position = 2)]
+ [PSFramework.Validation.PsfValidateScript('PSFramework.Validate.FSPath.Folder', ErrorString = 'PSFramework.Validate.FSPath.Folder')]
[string]
$OutPath = (Get-PSFConfigValue -FullName 'PSModuleDevelopment.Template.OutPath' -Fallback "."),
@@ -128,52 +129,31 @@
$EnableException
)
- begin
- {
- #region Validate output path
- try
- {
- $resolvedPath = Resolve-Path $OutPath -ErrorAction Stop
- if (($resolvedPath | Measure-Object).Count -ne 1)
- {
- throw "Cannot resolve $OutPath to a single folder"
- }
- if ($resolvedPath.Provider -notlike "*FileSystem")
- {
- throw "Path $OutPath was not recognized as a filesystem path"
- }
- }
- catch
- {
- Stop-PSFFunction -Message "Could not resolve output path to a valid folder: $OutPath" -EnableException $EnableException -ErrorRecord $_ -Tag 'fail', 'path', 'validate'
- return
- }
- #endregion Validate output path
-
+ begin {
$templates = @()
- switch ($PSCmdlet.ParameterSetName)
- {
+ switch ($PSCmdlet.ParameterSetName) {
'NameStore' { $templates = Get-PSMDTemplate -TemplateName $TemplateName -Store $Store }
'NamePath' { $templates = Get-PSMDTemplate -TemplateName $TemplateName -Path $Path }
}
+ if ($TemplateName -and -not $templates) {
+ Stop-PSFFunction -String 'Invoke-PSMDTemplate.Template.NotFound' -StringValues $TemplateName -EnableException $EnableException -Cmdlet $PSCmdlet
+ return
+ }
#region Parameter Processing
if (-not $Parameters) { $Parameters = @{ } }
if ($Name) { $Parameters["Name"] = $Name }
- foreach ($config in (Get-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.ParameterDefault.*'))
- {
+ foreach ($config in (Get-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.ParameterDefault.*')) {
$cfgName = $config.Name -replace '^.+\.([^\.]+)$', '$1'
- if (-not $Parameters.ContainsKey($cfgName))
- {
+ if (-not $Parameters.ContainsKey($cfgName)) {
$Parameters[$cfgName] = $config.Value
}
}
#endregion Parameter Processing
#region Helper function
- function Invoke-Template
- {
+ function Invoke-Template {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
[CmdletBinding()]
param (
@@ -200,16 +180,13 @@
)
Write-PSFMessage -Level Verbose -Message "Processing template $($item)" -Tag 'template', 'invoke' -FunctionName Invoke-PSMDTemplate
- $templateData = Import-Clixml -Path $Template.Path -ErrorAction Stop
+ $templateData = Import-PSFClixml -Path $Template.Path -ErrorAction Stop
#region Process Parameters
- foreach ($parameter in $templateData.Parameters)
- {
+ foreach ($parameter in $templateData.Parameters) {
if (-not $parameter) { continue }
- if (-not $Parameters.ContainsKey($parameter))
- {
+ if (-not $Parameters.ContainsKey($parameter)) {
if ($Silent) { throw "Parameter not specified: $parameter" }
- try
- {
+ try {
$value = Read-Host -Prompt "Enter value for parameter '$parameter'" -ErrorAction Stop
$Parameters[$parameter] = $value
}
@@ -221,17 +198,13 @@
#region Scripts
$scriptParameters = @{ }
- if (-not $Raw)
- {
- foreach ($scriptParam in $templateData.Scripts.Values)
- {
+ if (-not $Raw) {
+ foreach ($scriptParam in $templateData.Scripts.Values) {
if (-not $scriptParam) { continue }
try { $scriptParameters[$scriptParam.Name] = "$([scriptblock]::Create($scriptParam.StringScript).Invoke())" }
- catch
- {
+ catch {
if ($Silent) { throw (New-Object System.Exception("Scriptblock $($scriptParam.Name) failed during execution: $_", $_.Exception)) }
- else
- {
+ else {
Write-PSFMessage -Level Warning -Message "Scriptblock $($scriptParam.Name) failed during execution. Please specify a custom value or use CTRL+C to terminate creation" -ErrorRecord $_ -FunctionName "Invoke-PSMDTemplate" -ModuleName 'PSModuleDevelopment'
$scriptParameters[$scriptParam.Name] = Read-Host -Prompt "Value for script $($scriptParam.Name)"
}
@@ -240,17 +213,14 @@
}
#endregion Scripts
- switch ($templateData.Type.ToString())
- {
+ switch ($templateData.Type.ToString()) {
#region File
"File"
{
- foreach ($child in $templateData.Children)
- {
+ foreach ($child in $templateData.Children) {
Write-TemplateItem -Item $child -Path $OutPath -Encoding $Encoding -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
}
- if ($Raw -and $templateData.Scripts.Values)
- {
+ if ($Raw -and $templateData.Scripts.Values) {
$templateData.Scripts.Values | Export-Clixml -Path (Join-Path $OutPath "_PSMD_ParameterScripts.xml")
}
}
@@ -260,34 +230,28 @@
"Project"
{
#region Resolve output folder
- if (-not $NoFolder)
- {
- if ($Parameters["Name"])
- {
+ if (-not $NoFolder) {
+ if ($Parameters["Name"]) {
$projectName = $Parameters["Name"]
$projectFullName = Join-Path $OutPath $projectName
- if ((Test-Path $projectFullName) -and (-not $Force))
- {
+ if ((Test-Path $projectFullName) -and (-not $Force)) {
throw "Project root folder already exists: $projectFullName"
}
$newFolder = New-Item -Path $OutPath -Name $Parameters["Name"] -ItemType Directory -ErrorAction Stop -Force
}
- else
- {
+ else {
throw "Parameter Name is needed to create a project without setting the -NoFolder parameter!"
}
}
else { $newFolder = Get-Item $OutPath }
#endregion Resolve output folder
- foreach ($child in $templateData.Children)
- {
+ foreach ($child in $templateData.Children) {
Write-TemplateItem -Item $child -Path $newFolder.FullName -Encoding $Encoding -ParameterFlat $Parameters -ParameterScript $scriptParameters -Raw $Raw
}
#region Write Config File (Raw)
- if ($Raw)
- {
+ if ($Raw) {
$guid = [System.Guid]::NewGuid().ToString()
$optionsTemplate = @"
@{
@@ -299,11 +263,9 @@
þþþPLACEHOLDER-$($guid)þþþ
}
"@
- if ($params = $templateData.Scripts.Values)
- {
+ if ($params = $templateData.Scripts.Values) {
$list = @()
- foreach ($param in $params)
- {
+ foreach ($param in $params) {
$list += @"
$($param.Name) = {
$($param.StringScript)
@@ -312,9 +274,8 @@
}
$optionsTemplate = $optionsTemplate -replace "þþþPLACEHOLDER-$($guid)þþþ", ($list -join "`n`n")
}
- else
- {
- $optionsTemplate = $optionsTemplate -replace "þþþPLACEHOLDER-$($guid)þþþ",""
+ else {
+ $optionsTemplate = $optionsTemplate -replace "þþþPLACEHOLDER-$($guid)þþþ", ""
}
$configFile = Join-Path $newFolder.FullName "PSMDTemplate.ps1"
@@ -326,8 +287,7 @@
}
}
- function Write-TemplateItem
- {
+ function Write-TemplateItem {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
[CmdletBinding()]
param (
@@ -350,46 +310,37 @@
$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 file: $($Item.Name) ($($Item.RelativePath))" -FunctionName Invoke-PSMDTemplate -ModuleName PSModuleDevelopment -Tag 'create', 'template'
$identifier = $Item.Identifier
$isFile = $Item.GetType().Name -eq 'TemplateItemFile'
#region File
- if ($isFile)
- {
+ if ($isFile) {
$fileName = $Item.Name
- if (-not $Raw)
- {
- foreach ($param in $Item.FileSystemParameterFlat)
- {
- $fileName = $fileName -replace "$($identifier)$([regex]::Escape($param))$($identifier)",$ParameterFlat[$param]
+ if (-not $Raw) {
+ foreach ($param in $Item.FileSystemParameterFlat) {
+ $fileName = $fileName.Replace("$($identifier)$($param)$($identifier)", $ParameterFlat[$param], $true, $null)
}
- foreach ($param in $Item.FileSystemParameterScript)
- {
- $fileName = $fileName -replace "$($identifier)!$([regex]::Escape($param))!$($identifier)", $ParameterScript[$param]
+ foreach ($param in $Item.FileSystemParameterScript) {
+ $fileName = $fileName.Replace("$($identifier)$($param)$($identifier)", $ParameterScript[$param], $true, $null)
}
}
$destPath = Join-Path $Path $fileName
- if ($Item.PlainText)
- {
+ if ($Item.PlainText) {
$text = $Item.Value
- if (-not $Raw)
- {
- foreach ($param in $Item.ContentParameterFlat)
- {
- $text = $text -replace "$($identifier)$([regex]::Escape($param))$($identifier)", $ParameterFlat[$param]
+ if (-not $Raw) {
+ foreach ($param in $Item.ContentParameterFlat) {
+ $text = $text.Replace("$($identifier)$($param)$($identifier)", $ParameterFlat[$param], $true, $null)
}
- foreach ($param in $Item.ContentParameterScript)
- {
- $text = $text -replace "$($identifier)!$([regex]::Escape($param))!$($identifier)", $ParameterScript[$param]
+ foreach ($param in $Item.ContentParameterScript) {
+ $text = $text.Replace("$($identifier)!$($param)!$($identifier)", $ParameterScript[$param], $true, $null)
}
}
[System.IO.File]::WriteAllText($destPath, $text, $Encoding)
}
- else
- {
+ else {
$bytes = [System.Convert]::FromBase64String($Item.Value)
[System.IO.File]::WriteAllBytes($destPath, $bytes)
}
@@ -397,24 +348,19 @@
#endregion File
#region Folder
- else
- {
+ else {
$folderName = $Item.Name
- if (-not $Raw)
- {
- foreach ($param in $Item.FileSystemParameterFlat)
- {
+ if (-not $Raw) {
+ foreach ($param in $Item.FileSystemParameterFlat) {
$folderName = $folderName -replace "$($identifier)$([regex]::Escape($param))$($identifier)", $ParameterFlat[$param]
}
- foreach ($param in $Item.FileSystemParameterScript)
- {
+ foreach ($param in $Item.FileSystemParameterScript) {
$folderName = $folderName -replace "$($identifier)!$([regex]::Escape($param))!$($identifier)", $ParameterScript[$param]
}
}
$folder = New-Item -Path $Path -Name $folderName -ItemType Directory
- foreach ($child in $Item.Children)
- {
+ foreach ($child in $Item.Children) {
Write-TemplateItem -Item $child -Path $folder.FullName -Encoding $Encoding -ParameterFlat $ParameterFlat -ParameterScript $ParameterScript -Raw $Raw
}
}
@@ -422,27 +368,27 @@
}
#endregion Helper function
}
- process
- {
+ process {
if (Test-PSFFunctionInterrupt) { return }
- foreach ($item in $Template)
- {
- if ($PSCmdlet.ShouldProcess($item, "Invoking template"))
- {
- try { Invoke-Template -Template $item -OutPath $resolvedPath.ProviderPath -NoFolder $NoFolder -Encoding $Encoding -Parameters $Parameters.Clone() -Raw $Raw -Silent $Silent }
- catch { Stop-PSFFunction -Message "Failed to invoke template $($item)" -EnableException $EnableException -ErrorRecord $_ -Target $item -Tag 'fail', 'template', 'invoke' -Continue }
- }
+ $invokeParam = @{
+ Parameters = $Parameters.Clone()
+ OutPath = Resolve-PSFPath -Path $OutPath
+ NoFolder = $NoFolder
+ Encoding = $Encoding
+ Raw = $Raw
+ Silent = $Silent
}
- foreach ($item in $templates)
- {
- if ($PSCmdlet.ShouldProcess($item, "Invoking template"))
- {
- try { Invoke-Template -Template $item -OutPath $resolvedPath.ProviderPath -NoFolder $NoFolder -Encoding $Encoding -Parameters $Parameters.Clone() -Raw $Raw -Silent $Silent }
- catch { Stop-PSFFunction -Message "Failed to invoke template $($item)" -EnableException $EnableException -ErrorRecord $_ -Target $item -Tag 'fail', 'template', 'invoke' -Continue }
- }
+
+ foreach ($item in $Template) {
+ Invoke-PSFProtectedCommand -ActionString 'Invoke-PSMDTemplate.Invoking' -ActionStringValues $item -Target $item -ScriptBlock {
+ Invoke-Template @invokeParam -Template $item
+ } -EnableException $EnableException -PSCmdlet $PSCmdlet -Continue
+ }
+ foreach ($item in $templates) {
+ Invoke-PSFProtectedCommand -ActionString 'Invoke-PSMDTemplate.Invoking' -ActionStringValues $item -Target $item -ScriptBlock {
+ Invoke-Template @invokeParam -Template $item
+ } -EnableException $EnableException -PSCmdlet $PSCmdlet -Continue
}
}
-}
-
-if (-not (Test-Path Alias:\imt)) { Set-Alias -Name imt -Value Invoke-PSMDTemplate }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/templating/New-PSMDDotNetProject.ps1 b/PSModuleDevelopment/functions/templating/New-PSMDDotNetProject.ps1
index 8e2fdd8..a34ca7c 100644
--- a/PSModuleDevelopment/functions/templating/New-PSMDDotNetProject.ps1
+++ b/PSModuleDevelopment/functions/templating/New-PSMDDotNetProject.ps1
@@ -59,6 +59,7 @@
- It will skip the automatic restore of the project on create
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')]
+ [Alias('dotnetnew')]
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Create')]
Param (
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Create')]
@@ -175,6 +176,4 @@
& dotnet.exe new $dotNetArgs
}
}
-}
-
-New-Alias -Name dotnetnew -Value New-PSMDDotNetProject -Option AllScope -Scope Global -ErrorAction Ignore
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/utility/Find-PSMDFileContent.ps1 b/PSModuleDevelopment/functions/utility/Find-PSMDFileContent.ps1
index bf78b92..94094b0 100644
--- a/PSModuleDevelopment/functions/utility/Find-PSMDFileContent.ps1
+++ b/PSModuleDevelopment/functions/utility/Find-PSMDFileContent.ps1
@@ -31,6 +31,7 @@
Searches all module files for the string 'Get-Test'.
#>
+ [Alias('find')]
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, Position = 0)]
@@ -61,5 +62,4 @@
Get-ChildItem -Path $Path -Recurse | Where-Object Extension -Match $Extension | Select-String -Pattern $Pattern
}
-}
-New-Alias -Name find -Value Find-PSMDFileContent -Scope Global -Option AllScope
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1 b/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
index 0e34124..67a8a5a 100644
--- a/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
+++ b/PSModuleDevelopment/functions/utility/Restart-PSMDShell.ps1
@@ -39,6 +39,7 @@
Author: Friedrich Weinmann
Created on: August 6th, 2016
#>
+ [Alias('rss', 'Restart-Shell')]
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')]
Param (
[Switch]
@@ -72,6 +73,4 @@
if (-not $NoExit) { exit }
}
}
-}
-New-Alias -Name Restart-Shell -Value Restart-PSMDShell -Option AllScope -Scope Global
-New-Alias -Name rss -Value Restart-PSMDShell -Option AllScope -Scope Global
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/command.action.ps1 b/PSModuleDevelopment/internal/buildActions/command.action.ps1
new file mode 100644
index 0000000..9a8e034
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/command.action.ps1
@@ -0,0 +1,74 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ #region Process Parameters
+ if (-not $actualParameters.Command) {
+ throw "Mandatory parameter: Command not specified"
+ }
+
+ if ($actualParameters.Command -is [System.Management.Automation.ScriptBlock]) {
+ $scriptblock = $actualParameters.Command
+ }
+ else {
+ try { $scriptblock = [scriptblock]::Create($actualParameters.Command) }
+ catch {
+ throw "Error parsing command '$($actualParameters.Command)' : $_"
+ }
+ }
+
+ $actualArguments = foreach ($argument in $actualParameters.ArgumentList) {
+ if ($argument -isnot [string]) {
+ $argument
+ continue
+ }
+ if ($argument -notlike '%!*!%') {
+ $argument
+ continue
+ }
+ $artifactName = $argument -replace '^%!(.+)!%$', '$1'
+ $artifactObject = Get-PSMDBuildArtifact -Name $artifactName
+ if (-not $artifactObject) { throw "Artifact for arguments not found: $artifactName" }
+ $artifactObject.Value
+ }
+
+ $inSession = $null
+ if ($actualParameters.InSession) {
+ if ($actualParameters.InSession -is [System.Management.Automation.Runspaces.PSSession]) {
+ $inSession = $actualParameters.InSession
+ }
+ $artifactObject = Get-PSMDBuildArtifact -Name $actualParameters.InSession
+ if (-not $artifactObject) { throw "Artifact for parameter InSession not found: $($actualParameters.InSession)" }
+ if ($artifactObject.Value -isnot [System.Management.Automation.Runspaces.PSSession]) { throw "Artifact for parameter InSession ($($actualParameters.InSession)) is not a pssession!" }
+ $inSession = $artifactObject.Value
+ }
+ #endregion Process Parameters
+
+ #region Execution
+ $invokeParam = @{
+ ScriptBlock = $scriptblock
+ ArgumentList = $actualArguments
+ }
+ if ($inSession) { $invokeParam.Session = $inSession }
+ try { Invoke-Command @invokeParam -ErrorAction Stop }
+ catch { throw }
+ #endregion Execution
+}
+
+$params = @{
+ Name = 'command'
+ Action = $action
+ Description = 'Execute a scriptblock'
+ Parameters = @{
+ Command = '(mandatory) Scriptcode to run'
+ ArgumentList = 'Any number of arguments to pass to the command. To insert artifacts, specify a string with the special notation "%!ArtifactName!%"'
+ InSession = 'Execute the scriptfile in the target PSSession. Either provide a full session object or an artifact name pointing at one.'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/copy-item.action.ps1 b/PSModuleDevelopment/internal/buildActions/copy-item.action.ps1
new file mode 100644
index 0000000..bb8aa67
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/copy-item.action.ps1
@@ -0,0 +1,73 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ #region Utility Functions
+ function ConvertTo-PSSession {
+ [CmdletBinding()]
+ param (
+ [Parameter(ValueFromPipeline = $true)]
+ $InputObject
+ )
+ process {
+ if ($InputObject -is [System.Management.Automation.Runspaces.PSSession]) {
+ return $InputObject
+ }
+ $artifactValue = (Get-PSMDBuildArtifact -Name $InputObject).Value
+ if ($artifactValue -is [System.Management.Automation.Runspaces.PSSession]) {
+ return $artifactValue
+ }
+ }
+ }
+ #endregion Utility Functions
+
+ if (-not ($actualParameters.Path -and $actualParameters.Destination)) {
+ throw "Invalid parameters! Specify both Path and Destination."
+ }
+
+ $paths = $actualParameters.Path -replace '%ProjectRoot%', $rootPath
+ $copyParam = @{
+ Destination = $actualParameters.Destination -replace '%ProjectRoot%', $rootPath
+ }
+ if ($actualParameters.Recurse) { $copyParam.Recurse = $true }
+ if ($actualParameters.Force) { $copyParam.Force = $true }
+ if ($actualParameters.FromSession) {
+ $fromSession = $actualParameters.FromSession | ConvertTo-PSSession
+ if (-not $fromSession) {
+ throw "FromSession $($actualParameters.FromSession) not found!"
+ }
+ $copyParam.FromSession = $fromSession
+ }
+ if ($actualParameters.ToSession) {
+ $toSession = $actualParameters.ToSession | ConvertTo-PSSession
+ if (-not $toSession) {
+ throw "ToSession $($actualParameters.ToSession) not found!"
+ }
+ $copyParam.ToSession = $toSession
+ }
+ foreach ($path in $paths) {
+ try { Copy-Item @copyParam -Path $path -ErrorAction Stop }
+ catch { throw }
+ }
+}
+
+$params = @{
+ Name = 'copy-item'
+ Action = $action
+ Description = 'Copies files & folders from A to B'
+ Parameters = @{
+ Path = '(mandatory) Path(s) to copy. Use "%ProjectRoot%" to reference to the root path containing the build file.'
+ Destination = '(mandatory) Path to copy to. Use "%ProjectRoot%" to reference to the root path containing the build file.'
+ FromSession = 'Artifact Name of the PSSession to copy from.'
+ ToSession = 'Artifact Name of the PSSession to copy to.'
+ Recurse = 'Whether to copy child items'
+ Force = 'Whether to use force (Remove destination items)'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/new-pssession.action.ps1 b/PSModuleDevelopment/internal/buildActions/new-pssession.action.ps1
new file mode 100644
index 0000000..6406f4e
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/new-pssession.action.ps1
@@ -0,0 +1,44 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ if (-not $actualParameters.ArtifactName) { throw "No ArtifactName specified! Unable to publish remoting session for build." }
+ if (-not ($actualParameters.VMName -or $actualParameters.ComputerName)) { throw "Neither ComputerName nor VMName specified, unable to connect to nothing!" }
+ if ($actualParameters.VMName -and $actualParameters.ComputerName) { throw "Both ComputerName and VMName specified, unable to connect to both at once!" }
+
+ $credential = $null
+ if ($actualParameters.CredentialPath) {
+ $path = $actualParameters.CredentialPath -replace '%ProjectRoot%', $rootPath
+ try { $credential = Import-PSFClixml -Path $path -ErrorAction Stop }
+ catch { throw "Error accessing credentials from $path : $_" }
+ }
+
+ $paramNewPSSession = @{ }
+ if ($actualParameters.VMName) { $paramNewPSSession.VMName = $actualParameters.VMName }
+ if ($actualParameters.ComputerName) { $paramNewPSSession.ComputerName = $actualParameters.ComputerName }
+ if ($credential) { $paramNewPSSession.Credential = $credential }
+
+ try { $session = New-PSSession @paramNewPSSession -ErrorAction Stop }
+ catch { throw "Error establishing PS Remoting session: $_" }
+
+ Publish-PSMDBuildArtifact -Name $actualParameters.ArtifactName -Value $session -Tag pssession
+}
+
+$params = @{
+ Name = 'new-pssession'
+ Action = $action
+ Description = 'Establish a PSSession to a target computer and provide it as an artifact'
+ Parameters = @{
+ ComputerName = 'The Computer to connect to'
+ VMName = 'The virtual machine to which to connect to via the HyperV VM Bus'
+ CredentialPath = 'The path to the credentials to use for the connection. Use %ProjectRoot% to insert the folder path to where the buildfile is located'
+ ArtifactName = '(mandatory) The name under which to publish the session as an artifact'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/remove-item.action.ps1 b/PSModuleDevelopment/internal/buildActions/remove-item.action.ps1
new file mode 100644
index 0000000..624ac1b
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/remove-item.action.ps1
@@ -0,0 +1,64 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ if (-not $actualParameters.Path) {
+ throw "Invalid parameters! Specify a Path to delete."
+ }
+
+ $paths = $actualParameters.Path -replace '%ProjectRoot%', $rootPath
+ $deleteParam = @{ }
+ if ($actualParameters.Recurse) { $deleteParam.Recurse = $true }
+ if ($actualParameters.Force) { $deleteParam.Force = $true }
+
+ $inSession = $null
+ if ($actualParameters.InSession) {
+ if ($actualParameters.InSession -is [System.Management.Automation.Runspaces.PSSession]) {
+ $inSession = $actualParameters.InSession
+ }
+ $artifactObject = Get-PSMDBuildArtifact -Name $actualParameters.InSession
+ if (-not $artifactObject) { throw "Artifact for parameter InSession not found: $($actualParameters.InSession)" }
+ if ($artifactObject.Value -isnot [System.Management.Automation.Runspaces.PSSession]) { throw "Artifact for parameter InSession ($($actualParameters.InSession)) is not a pssession!" }
+ $inSession = $artifactObject.Value
+ }
+
+ if ($inSession) {
+ $failed = Invoke-Command -Session $inSession -ScriptBlock {
+ param ($DeleteParam, $Paths)
+
+ foreach ($path in $Paths) {
+ if (-not (Get-Item -Path $path -Force -ErrorAction Ignore)) { continue }
+ try { Remove-Item @DeleteParam -Path $path -ErrorAction Stop }
+ catch { return $_ }
+ }
+ } -ArgumentList $deleteParam, $paths
+ if ($failed) {
+ throw $failed
+ }
+ }
+
+ foreach ($path in $paths) {
+ if (-not (Get-Item -Path $path -Force -ErrorAction Ignore)) { continue }
+ try { Remove-Item @DeleteParam -Path $path -ErrorAction Stop }
+ catch { throw }
+ }
+}
+
+$params = @{
+ Name = 'remove-item'
+ Action = $action
+ Description = 'Removes files or folders'
+ Parameters = @{
+ Path = '(mandatory) Path(s) to the item(s) to delete. Use "%ProjectRoot%" to reference to the root path containing the build file.'
+ InSession = 'Artifact Name of the PSSession within which to execute the deletion'
+ Recurse = 'Whether to delete child items'
+ Force = 'Whether to use force'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/remove-pssession.action.ps1 b/PSModuleDevelopment/internal/buildActions/remove-pssession.action.ps1
new file mode 100644
index 0000000..a6e80e5
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/remove-pssession.action.ps1
@@ -0,0 +1,48 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ if ($actualParameters.All) {
+ foreach ($artifact in Get-PSMDBuildArtifact -Tag pssession) {
+ try {
+ $artifact.Value | Remove-PSSession -ErrorAction Stop
+ Remove-PSMDBuildArtifact -Name $artifact.Name
+ }
+ catch {
+ throw "Failed to remove PSSession artifact $($artifact.Name) to $($artifact.Value) | $_"
+ }
+ }
+ }
+ elseif ($actualParameters.ArtifactName) {
+ $artifact = Get-PSMDBuildArtifact -Name $actualParameters.ArtifactName
+ if ($artifact) {
+ try {
+ $artifact.Value | Remove-PSSession -ErrorAction Stop
+ Remove-PSMDBuildArtifact -Name $artifact.Name
+ }
+ catch {
+ throw "Failed to remove PSSession artifact $($artifact.Name) to $($artifact.Value) | $_"
+ }
+ }
+ }
+ else {
+ throw "Invalid parameters! Specify either 'All' or 'ArtifactName' in step definition."
+ }
+}
+
+$params = @{
+ Name = 'remove-pssession'
+ Action = $action
+ Description = 'Removes a PSSession that was previously established with the new-pssession action'
+ Parameters = @{
+ ArtifactName = 'The name under which to publish the session as an artifact'
+ All = 'Whether all PSSession artifacts should be removed'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/buildActions/script.action.ps1 b/PSModuleDevelopment/internal/buildActions/script.action.ps1
new file mode 100644
index 0000000..6826213
--- /dev/null
+++ b/PSModuleDevelopment/internal/buildActions/script.action.ps1
@@ -0,0 +1,70 @@
+$action = {
+ param (
+ $Parameters
+ )
+
+ $rootPath = $Parameters.RootPath
+ $actualParameters = $Parameters.Parameters
+ $actualParameters = Resolve-PSMDBuildStepParameter -Parameters $actualParameters -FromArtifacts $Parameters.ParametersFromArtifacts -ProjectName $Parameters.ProjectName -StepName $Parameters.StepName
+
+ #region Process Parameters
+ if (-not $actualParameters.Path) {
+ throw "Mandatory parameter: Path not specified"
+ }
+
+ $scriptPath = $actualParameters.Path -replace '%ProjectRoot%', $rootPath
+
+ if (-not (Test-Path $scriptPath)) {
+ throw "Cannot find resolved script path: $scriptPath"
+ }
+
+ $actualArguments = foreach ($argument in $actualParameters.ArgumentList) {
+ if ($argument -isnot [string]) {
+ $argument
+ continue
+ }
+ if ($argument -notlike '%!*!%') {
+ $argument
+ continue
+ }
+ $artifactName = $argument -replace '^%!(.+)!%$', '$1'
+ $artifactObject = Get-PSMDBuildArtifact -Name $artifactName
+ if (-not $artifactObject) { throw "Artifact for arguments not found: $artifactName" }
+ $artifactObject.Value
+ }
+
+ $inSession = $null
+ if ($actualParameters.InSession) {
+ if ($actualParameters.InSession -is [System.Management.Automation.Runspaces.PSSession]) {
+ $inSession = $actualParameters.InSession
+ }
+ $artifactObject = Get-PSMDBuildArtifact -Name $actualParameters.InSession
+ if (-not $artifactObject) { throw "Artifact for parameter InSession not found: $($actualParameters.InSession)" }
+ if ($artifactObject.Value -isnot [System.Management.Automation.Runspaces.PSSession]) { throw "Artifact for parameter InSession ($($actualParameters.InSession)) is not a pssession!" }
+ $inSession = $artifactObject.Value
+ }
+ #endregion Process Parameters
+
+ #region Execution
+ $invokeParam = @{
+ FilePath = $scriptPath
+ ArgumentList = $actualArguments
+ }
+ if ($inSession) { $invokeParam.Session = $inSession }
+ try { Invoke-Command @invokeParam -ErrorAction Stop }
+ catch { throw }
+ #endregion Execution
+}
+
+$params = @{
+ Name = 'script'
+ Action = $action
+ Description = 'Execute a scriptfile'
+ Parameters = @{
+ Path = '(mandatory) Path to the scriptfile to run. Use %ProjectRoot% to reference the same folder the build action file is stored in.'
+ ArgumentList = 'Any number of arguments to pass to the scripts. To insert artifacts, specify a string with the special notation "%!ArtifactName!%"'
+ InSession = 'Execute the scriptfile in the target PSSession. Either provide a full session object or an artifact name pointing at one.'
+ }
+}
+
+Register-PSMDBuildAction @params
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/configurations/build.ps1 b/PSModuleDevelopment/internal/configurations/build.ps1
new file mode 100644
index 0000000..291bf24
--- /dev/null
+++ b/PSModuleDevelopment/internal/configurations/build.ps1
@@ -0,0 +1 @@
+Set-PSFConfig -Module PSModuleDevelopment -Name 'Build.Project.Selected' -Value '' -Validation string -Initialize -Description 'Path of the selected build project. Used when running Invoke-PSMDBuildProject without specifying a build file.'
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/configurations/debug.ps1 b/PSModuleDevelopment/internal/configurations/debug.ps1
index 51e68c0..d6999b3 100644
--- a/PSModuleDevelopment/internal/configurations/debug.ps1
+++ b/PSModuleDevelopment/internal/configurations/debug.ps1
@@ -1 +1 @@
-Set-PSFConfig -Module PSModuleDevelopment -Name 'Debug.ConfigPath' -Value "$($path_FileUserShared)\InfernalAssociates\PowerShell\PSModuleDevelopment\config.xml" -Initialize -Validation string -Description 'The path to where the module debugging information is being stored. Used in the *-PSMDModuleDebug commands.'
\ No newline at end of file
+Set-PSFConfig -Module PSModuleDevelopment -Name 'Debug.ConfigPath' -Value (Join-Path -Path (Get-PSFPath -Name AppData) -ChildPath "InfernalAssociates/PowerShell/PSModuleDevelopment/config.xml") -Initialize -Validation string -Description 'The path to where the module debugging information is being stored. Used in the *-PSMDModuleDebug commands.'
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/configurations/template.ps1 b/PSModuleDevelopment/internal/configurations/template.ps1
index f1065ad..79a6981 100644
--- a/PSModuleDevelopment/internal/configurations/template.ps1
+++ b/PSModuleDevelopment/internal/configurations/template.ps1
@@ -9,7 +9,7 @@ Set-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.ParameterDefault.Com
Set-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.BinaryExtensions' -Value @('.dll', '.exe', '.pdf', '.doc', '.docx', '.xls', '.xlsx') -Initialize -Description "When creating a template, files with these extensions will be included as raw bytes and not interpreted for parameter insertion."
# Define the default store. To add more stores, just add a similar setting with a different last name segment
-Set-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.Store.Default' -Value "$path_FileUserShared/WindowsPowerShell/PSModuleDevelopment/Templates" -Initialize -Validation "string" -Description "Path to the default directory where PSModuleDevelopment will store its templates. You can add additional stores by creating the same setting again, only changing the last name segment to a new name and configuring a separate path."
+Set-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.Store.Default' -Value (Join-Path -Path (Get-PSFPath -Name AppData) -ChildPath "WindowsPowerShell/PSModuleDevelopment/Templates") -Initialize -Validation "string" -Description "Path to the default directory where PSModuleDevelopment will store its templates. You can add additional stores by creating the same setting again, only changing the last name segment to a new name and configuring a separate path."
Set-PSFConfig -Module 'PSModuleDevelopment' -Name 'Template.Store.PSModuleDevelopment' -Value "$script:ModuleRoot/internal/templates" -Initialize -Validation "string" -Description "Path to the templates shipped in PSModuleDevelopment"
# Define the default path to create from templates in
diff --git a/PSModuleDevelopment/internal/configurations/utility.ps1 b/PSModuleDevelopment/internal/configurations/utility.ps1
index 6bf4866..bddf4d2 100644
--- a/PSModuleDevelopment/internal/configurations/utility.ps1
+++ b/PSModuleDevelopment/internal/configurations/utility.ps1
@@ -1,5 +1,5 @@
Set-PSFConfig -Module PSModuleDevelopment -Name 'Module.Path' -Value "" -Initialize -Validation "string" -Handler { } -Description "The path to the module currently under development. Used as default path by commnds that work within a module directory."
-Set-PSFConfig -Module PSModuleDevelopment -Name 'Package.Path' -Value "$env:TEMP" -Initialize -Validation "string" -Description "The default output path when exporting a module into a nuget package."
+Set-PSFConfig -Module PSModuleDevelopment -Name 'Package.Path' -Value (Get-PSFPath -Name Temp) -Initialize -Validation "string" -Description "The default output path when exporting a module into a nuget package."
Set-PSFConfig -Module PSModuleDevelopment -Name 'Find.DefaultExtensions' -Value '^\.ps1$|^\.psd1$|^\.psm1$|^\.cs$' -Initialize -Validation string -Description 'The pattern to use to select files to scan when using Find-PSMDFileContent.'
Set-PSFConfig -Module PSModuleDevelopment -Name "ShowSyntax.ParmsNotFound" -Value "Red" -Initialize -Validation "string" -Handler { } -Description "The color to be used for the parameters that could not be found."
diff --git a/PSModuleDevelopment/internal/functions/build/Export-PsmdBuildProjectFile.ps1 b/PSModuleDevelopment/internal/functions/build/Export-PsmdBuildProjectFile.ps1
new file mode 100644
index 0000000..1759ba6
--- /dev/null
+++ b/PSModuleDevelopment/internal/functions/build/Export-PsmdBuildProjectFile.ps1
@@ -0,0 +1,48 @@
+function Export-PsmdBuildProjectFile {
+<#
+ .SYNOPSIS
+ Exports a build project object to file.
+
+ .DESCRIPTION
+ Exports a build project object to file.
+ Strips out all superfluous properties on steps to improve readability of output.
+
+ .PARAMETER OutPath
+ The path to write the file to.
+
+ .PARAMETER ProjectObject
+ The build project to export.
+
+ .EXAMPLE
+ PS C:\> $projectObject | Export-PsmdBuildProjectFile -OutPath $outPath
+
+ Exports the specified build project object to file.
+#>
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string]
+ $OutPath,
+
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
+ $ProjectObject
+ )
+
+ process {
+ $steps = foreach ($step in $ProjectObject.Steps) {
+ $newStep = $step | ConvertTo-PSFHashtable -Include Name, Weight, Action
+ if ($step.Dependency) { $newStep.Dependency = $step.Dependency }
+ if ($step.Parameters) {
+ $parameters = $step.Parameters | ConvertTo-PSFHashtable
+ if ($parameters.Count -gt 0) { $newStep.Parameters = $parameters }
+ }
+ if ($step.Condition -and $step.ConditionSet) {
+ $newStep.Condition = $step.Condition
+ $newStep.ConditionSet = $step.ConditionSet
+ }
+ [PSCustomObject]$newStep
+ }
+ $ProjectObject.Steps = $steps | Sort-Object Weight
+ $ProjectObject | ConvertTo-Json -Depth 10 | Set-Content -Path $OutPath -Encoding UTF8 -ErrorAction Stop
+ }
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/internal/scripts/postimport.ps1 b/PSModuleDevelopment/internal/scripts/postimport.ps1
index 5b93318..51a1137 100644
--- a/PSModuleDevelopment/internal/scripts/postimport.ps1
+++ b/PSModuleDevelopment/internal/scripts/postimport.ps1
@@ -21,6 +21,11 @@ foreach ($file in (Get-ChildItem "$($script:ModuleRoot)\internal\maintenance\*.p
. Import-ModuleFile -Path $file.FullName
}
+# Load Build Actions
+foreach ($file in (Get-ChildItem "$($script:ModuleRoot)\internal\buildActions\*.ps1" -ErrorAction Ignore)) {
+ . Import-ModuleFile -Path $file.FullName
+}
+
# Load License
. Import-ModuleFile -Path "$($script:ModuleRoot)\internal\scripts\license.ps1"
diff --git a/PSModuleDevelopment/internal/scripts/variables.ps1 b/PSModuleDevelopment/internal/scripts/variables.ps1
index ef13dc1..30d090d 100644
--- a/PSModuleDevelopment/internal/scripts/variables.ps1
+++ b/PSModuleDevelopment/internal/scripts/variables.ps1
@@ -11,4 +11,8 @@ else
# Defaults to $Env:AppData on Windows
$path_FileUserShared = Join-Path $Env:AppData "$psVersionName\PSFramework\Config"
if (-not $Env:AppData) { $path_FileUserShared = Join-Path ([Environment]::GetFolderPath("ApplicationData")) "$psVersionName\PSFramework\Config" }
-}
\ No newline at end of file
+}
+
+# Store of registered build actions
+$script:buildActions = @{ }
+$script:buildArtifacts = @{ }
diff --git a/PSModuleDevelopment/internal/tepp/build.tepp.ps1 b/PSModuleDevelopment/internal/tepp/build.tepp.ps1
new file mode 100644
index 0000000..e430665
--- /dev/null
+++ b/PSModuleDevelopment/internal/tepp/build.tepp.ps1
@@ -0,0 +1,3 @@
+Register-PSFTeppScriptblock -Name 'PSModuleDevelopment.Build.Action' -ScriptBlock {
+ (Get-PSMDBuildAction).Name
+}
\ No newline at end of file
diff --git a/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml b/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
index 5351685..19a6410 100644
--- a/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
+++ b/PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml
@@ -1,6 +1,45 @@
+
+
+ PSModuleDevelopment.Build.StepResult
+
+ PSModuleDevelopment.Build.StepResult
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Count
+
+
+ Action
+
+
+ Status
+
+
+ Step
+
+
+ Data
+
+
+
+
+
+
+
PSModuleDevelopment.File.Command
diff --git a/build/filesAfter.txt b/build/filesAfter.txt
index fbf452a..92c18a9 100644
--- a/build/filesAfter.txt
+++ b/build/filesAfter.txt
@@ -5,5 +5,6 @@ internal\scriptblocks\*.ps1
internal\tepp\*.tepp.ps1
internal\tepp\assignment.ps1
internal\maintenance\*.ps1
+internal\buildActions\*.ps1
internal\scripts\license.ps1
internal\scripts\moduledebug.ps1
\ No newline at end of file
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj b/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
index 25f15a9..2673b30 100644
--- a/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj
@@ -31,6 +31,10 @@
4
+
+ ..\..\..\..\psframework\PSFramework\bin\PSFramework.dll
+ False
+
@@ -54,7 +58,11 @@
+
+
+
+
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterBase.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterBase.cs
new file mode 100644
index 0000000..451f9ce
--- /dev/null
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterBase.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace PSModuleDevelopment.Template.Parameter
+{
+ ///
+ /// Base class for all kinds of parameters gen 2+
+ ///
+ [Serializable]
+ public abstract class ParameterBase
+ {
+ ///
+ /// Name of the parameter
+ ///
+ public string Name;
+
+ ///
+ /// Description of the parameter
+ ///
+ public string Description;
+
+ ///
+ /// Get the value associated with this parameter
+ ///
+ /// The value to insert into the artifact generated from the template
+ public abstract string GetValue();
+ }
+}
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterPrompt.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterPrompt.cs
new file mode 100644
index 0000000..c96803e
--- /dev/null
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterPrompt.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace PSModuleDevelopment.Template.Parameter
+{
+ ///
+ /// A template parameter where the user is prompted for input.
+ ///
+ [Serializable]
+ public class ParameterPrompt : ParameterBase
+ {
+ ///
+ /// The value provided by the user
+ ///
+ public string Value;
+
+ ///
+ /// List of legal values to provide
+ ///
+ public List ValidateSet = new List();
+
+ ///
+ /// A validation pattern that needs to be met.
+ ///
+ public string ValidatePattern;
+
+ ///
+ /// An error description that will be shown if the user provides invalid input to a parameter with pattern validation.
+ ///
+ public string PatternError;
+
+ ///
+ /// Test whether the input meets the validation rules
+ ///
+ /// The value to test
+ /// Whether the value is valid.
+ public bool TestValue(string Value)
+ {
+ if (ValidateSet.Count > 0 && !ValidateSet.Contains(Value, StringComparer.InvariantCultureIgnoreCase))
+ return false;
+ if (!String.IsNullOrEmpty(ValidatePattern) && !Regex.IsMatch(Value, ValidatePattern))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Return the value specified by the user.
+ ///
+ /// The value specified by the user
+ public override string GetValue()
+ {
+ return Value;
+ }
+ }
+}
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterScript.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterScript.cs
new file mode 100644
index 0000000..c757440
--- /dev/null
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ParameterScript.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Management.Automation;
+using System.Text;
+using System.Threading.Tasks;
+
+using PSFramework.Utility;
+
+namespace PSModuleDevelopment.Template.Parameter
+{
+ ///
+ /// Parameter type executing
+ ///
+ [Serializable]
+ public class ParameterScript : ParameterBase
+ {
+ ///
+ /// The scriptblock to execute.
+ /// Wrapped as string for serialization purposes.
+ ///
+ public string ScriptBlock
+ {
+ get
+ {
+ if (_ScriptBlock == null)
+ return "";
+ return _ScriptBlock.ToString();
+ }
+ set
+ {
+ _ScriptBlock = new PsfScriptBlock(System.Management.Automation.ScriptBlock.Create(value));
+ }
+ }
+ private PsfScriptBlock _ScriptBlock;
+
+ ///
+ /// The value of the scriptblock.
+ /// Populated by the GetValue() method usually called with the "StartUp" timing.
+ ///
+ public string Value;
+
+ ///
+ /// When exactly during the template process should this scriptblock be executed?
+ ///
+ public ScriptExecutionTime Timing = ScriptExecutionTime.StartUp;
+
+ ///
+ /// Setting this to true will cause the Invoke-PSMDTemplate command to omit inserting values for the
+ ///
+ public bool SkipInsert;
+
+ ///
+ /// Returns the string value of the scriptblock by executing it!
+ ///
+ /// The string value of the scriptblock by executing it!
+ public override string GetValue()
+ {
+ if (String.IsNullOrEmpty(Value))
+ try { Value = (string)LanguagePrimitives.ConvertTo(_ScriptBlock.InvokeEx(true, true, false), typeof(string)); }
+ catch (Exception e) { Value = $""; }
+ return Value;
+ }
+
+ ///
+ /// Execute the scriptblock "Just-in-time" during either PreItemCreation or PostItemCreation Timing.
+ ///
+ /// The file/directory info object of the object recently or about to be created
+ /// Returns a string value resulting from the scriptblock to insert
+ public string GetInTimeValue(FileSystemInfo Info)
+ {
+ try { return (string)LanguagePrimitives.ConvertTo(_ScriptBlock.InvokeEx(Info, true, true, false), typeof(string)); }
+ catch (Exception e) { return $""; }
+ }
+
+ ///
+ /// Execute the scriptblock "Just-in-time" during either PreItemCreation or PostItemCreation Timing.
+ ///
+ /// The path to the file/directory info object of the object recently or about to be created
+ /// Whether the object (about to be) created is a file.
+ /// Returns a string value resulting from the scriptblock to insert
+ public string GetInTimeValue(string Path, bool IsFile)
+ {
+ if (IsFile)
+ return GetInTimeValue(new FileInfo(Path));
+ return GetInTimeValue(new DirectoryInfo(Path));
+ }
+ }
+}
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ScriptExecutionTime.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ScriptExecutionTime.cs
new file mode 100644
index 0000000..e8a797e
--- /dev/null
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Parameter/ScriptExecutionTime.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PSModuleDevelopment.Template.Parameter
+{
+ ///
+ /// When will a specific scriptblock parameter be executed?
+ ///
+ public enum ScriptExecutionTime
+ {
+ ///
+ /// Executed when starting the overall template invocation
+ ///
+ StartUp = 1,
+
+ ///
+ /// Executed before an individual item using it is created.
+ /// Values will be inserted into the file-content before writing to disk if applicable.
+ ///
+ PreItemCreation = 2,
+
+ ///
+ /// Executed after the individual item using it has been created.
+ /// Output will be discarded, but scriptblock will receive path of file / folder.
+ ///
+ PostItemCreation = 3,
+
+ ///
+ /// Executed after the entire project has been written.
+ /// Enables post-processing.
+ ///
+ Conclusion = 4
+ }
+}
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs
index 77b7ff8..0fa0d85 100644
--- a/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/Template.cs
@@ -58,26 +58,41 @@ public class Template
///
public Dictionary Scripts = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ ///
+ /// List of generation 2 parameters to include
+ ///
+ public Dictionary Parameters2 = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
///
/// Items in the root directory of the template (which may contain children themselves).
///
public List Children = new List();
+ ///
+ /// What design generation is the template?
+ ///
+ public int Generation = 1;
+
///
/// Returns the template digest used as index file.
///
/// A TemplateInfo object describing this template.
public TemplateInfo ToTemplateInfo()
{
+ List parameters = new List(Parameters);
+ if (Parameters2.Count > 0)
+ parameters.AddRange(Parameters2.Values.Where(o => o.GetType().Name == "ParameterPrompt").Select(o => o.Name));
+
TemplateInfo info = new TemplateInfo();
info.Author = Author;
info.CreatedOn = CreatedOn;
info.Description = Description;
info.Name = Name;
- info.Parameters = Parameters;
+ info.Parameters = parameters;
info.Tags = Tags;
info.Type = Type;
info.Version = Version;
+ info.Generation = Generation;
return info;
}
diff --git a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateInfo.cs b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateInfo.cs
index 586bc40..26f956e 100644
--- a/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateInfo.cs
+++ b/library/PSModuleDevelopment/PSModuleDevelopment/Template/TemplateInfo.cs
@@ -62,6 +62,11 @@ public class TemplateInfo
///
public string Path;
+ ///
+ /// What template generation is this file?
+ ///
+ public int Generation = 1;
+
///
/// The version-qualified name of the template
///
diff --git a/templates/AzureFunction/PSMDTemplate.ps1 b/templates/AzureFunction/PSMDTemplate.ps1
index b77849a..131be22 100644
--- a/templates/AzureFunction/PSMDTemplate.ps1
+++ b/templates/AzureFunction/PSMDTemplate.ps1
@@ -1,10 +1,11 @@
@{
- TemplateName = 'AzureFunction'
- Version = "1.0.0.0"
- AutoIncrementVersion = $true
- Tags = 'azure', 'function'
- Author = 'Friedrich Weinmann'
- Description = 'Basic Azure Function Template'
- Exclusions = @("PSMDInvoke.ps1", ".PSMDDependency") # Contains list of files - relative path to root - to ignore when building the template
- Scripts = @{ }
+ TemplateName = 'AzureFunction'
+ Version = "2.0.0"
+ AutoIncrementVersion = $true
+ Tags = 'azure', 'function'
+ Author = 'Friedrich Weinmann'
+ Description = 'Basic Azure Function Template'
+ Exclusions = @("PSMDInvoke.ps1", ".PSMDDependency") # Contains list of files - relative path to root - to ignore when building the template
+ Scripts = @{ }
+ NoFolder = $true # Whether invoking this template should generate a new folder ... or not.
}
\ No newline at end of file
diff --git a/templates/AzureFunction/build/build.ps1 b/templates/AzureFunction/build/build.ps1
new file mode 100644
index 0000000..9a79a68
--- /dev/null
+++ b/templates/AzureFunction/build/build.ps1
@@ -0,0 +1,23 @@
+param (
+ [string]
+ $Repository = 'PSGallery'
+)
+$workingDirectory = Split-Path $PSScriptRoot
+
+# Prepare output path and copy function folder
+Remove-Item -Path "$workingDirectory/publish" -Recurse -Force -ErrorAction Ignore
+$buildFolder = New-Item -Path $workingDirectory -Name 'publish' -ItemType Directory -Force -ErrorAction Stop
+Copy-Item -Path "$workingDirectory/function/*" -Destination $buildFolder.FullName -Recurse -Force
+
+# Process Dependencies
+$requiredModules = (Import-PowerShellDataFile -Path "$workingDirectory/þnameþ/þnameþ.psd1").RequiredModules
+foreach ($module in $requiredModules) {
+ Save-Module -Name $module -Path "$($buildFolder.FullName)/modules" -Force -Repository $Repository
+}
+
+# Process Function Module
+Copy-Item -Path "$workingDirectory/þnameþ" -Destination "$($buildFolder.FullName)/modules" -Force -Recurse
+
+# Package & Cleanup
+Compress-Archive -Path "$($buildFolder.FullName)/*" -DestinationPath "$workingDirectory/Function.zip"
+Remove-Item -Path $buildFolder.FullName -Recurse -Force -ErrorAction Ignore
\ No newline at end of file
diff --git a/templates/AzureFunction/host.json b/templates/AzureFunction/function/host.json
similarity index 100%
rename from templates/AzureFunction/host.json
rename to templates/AzureFunction/function/host.json
diff --git a/templates/AzureFunction/modules/readme.md b/templates/AzureFunction/function/modules/readme.md
similarity index 100%
rename from templates/AzureFunction/modules/readme.md
rename to templates/AzureFunction/function/modules/readme.md
diff --git a/templates/AzureFunction/function/profile.ps1 b/templates/AzureFunction/function/profile.ps1
new file mode 100644
index 0000000..be04a7d
--- /dev/null
+++ b/templates/AzureFunction/function/profile.ps1
@@ -0,0 +1,132 @@
+# Azure Functions profile.ps1
+#
+# This profile.ps1 will get executed every "cold start" of your Function App.
+# "cold start" occurs when:
+#
+# * A Function App starts up for the very first time
+# * A Function App starts up after being de-allocated due to inactivity
+#
+# You can define helper functions, run commands, or specify environment variables
+# NOTE: any variables defined that are not environment variables will get reset after the first execution
+# Authenticate with Azure PowerShell using MSI.
+# Remove this if you are not planning on using MSI or Azure PowerShell.
+
+if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts))
+{
+ Connect-AzAccount -Identity
+}
+
+# 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
diff --git a/templates/AzureFunction/requirements.psd1 b/templates/AzureFunction/function/requirements.psd1
similarity index 100%
rename from templates/AzureFunction/requirements.psd1
rename to templates/AzureFunction/function/requirements.psd1
diff --git a/templates/AzureFunction/profile.ps1 b/templates/AzureFunction/profile.ps1
deleted file mode 100644
index 3d09b77..0000000
--- a/templates/AzureFunction/profile.ps1
+++ /dev/null
@@ -1,21 +0,0 @@
-# Azure Functions profile.ps1
-#
-# This profile.ps1 will get executed every "cold start" of your Function App.
-# "cold start" occurs when:
-#
-# * A Function App starts up for the very first time
-# * A Function App starts up after being de-allocated due to inactivity
-#
-# You can define helper functions, run commands, or specify environment variables
-# NOTE: any variables defined that are not environment variables will get reset after the first execution
-# Authenticate with Azure PowerShell using MSI.
-# Remove this if you are not planning on using MSI or Azure PowerShell.
-
-if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts))
-{
- Connect-AzAccount -Identity
-}
-
-# 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.
\ No newline at end of file
diff --git "a/templates/AzureFunction/\303\276name\303\276/functions/readme.md" "b/templates/AzureFunction/\303\276name\303\276/functions/readme.md"
new file mode 100644
index 0000000..81c52a2
--- /dev/null
+++ "b/templates/AzureFunction/\303\276name\303\276/functions/readme.md"
@@ -0,0 +1,3 @@
+# Functions
+
+Place all your function code here
diff --git "a/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psd1" "b/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psd1"
new file mode 100644
index 0000000..9c8f039
--- /dev/null
+++ "b/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psd1"
@@ -0,0 +1,103 @@
+@{
+
+ # 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 = 'þ{ New-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 = ''
+
+ # 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 = @('bin\my.dll')
+
+ # 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
+}
\ No newline at end of file
diff --git "a/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psm1" "b/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psm1"
new file mode 100644
index 0000000..2509b6f
--- /dev/null
+++ "b/templates/AzureFunction/\303\276name\303\276/\303\276name\303\276.psm1"
@@ -0,0 +1,3 @@
+foreach ($file in Get-ChildItem $PSScriptRoot\functions -Recurse -Filter '*.ps1') {
+ . $file.FullName
+}
\ No newline at end of file
diff --git a/templates/AzureFunctionRest/run.ps1 b/templates/AzureFunctionRest/run.ps1
index 1f5b0ea..6c6cc83 100644
--- a/templates/AzureFunctionRest/run.ps1
+++ b/templates/AzureFunctionRest/run.ps1
@@ -1,33 +1,18 @@
-using namespace System.Net
-
-# Input bindings are passed in via param block.
-param ($Request,
+param (
+ $Request,
- $TriggerMetadata)
+ $TriggerMetadata
+)
-# Write to the Azure Functions log stream.
-Write-Host "PowerShell HTTP trigger function processed a request."
-# Interact with query parameters or the body of the request.
-$name = $Request.Query.Name
-if (-not $name)
-{
- $name = $Request.Body.Name
-}
+Write-Host "Trigger: þnameþ has been invoked"
-if ($name)
-{
- $status = [HttpStatusCode]::OK
- $body = "Hello $name"
-}
-else
-{
- $status = [HttpStatusCode]::BadRequest
- $body = "Please pass a name on the query string or in the request body."
-}
+$parameters = Get-RestParameter -Request $Request -Command þnameþ
-# Associate values to output bindings by calling 'Push-OutputBinding'.
-Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
- StatusCode = $status
- Body = $body
- })
+try { $results = þnameþ @parameters -ErrorAction Stop }
+catch {
+ Write-FunctionResult -Status InternalServerError -Body $_
+ $_ | Out-Host
+ return
+}
+Write-FunctionResult -Status OK -Body $results
\ No newline at end of file
diff --git a/templates/PSFProject/.github/FUNDING.yml b/templates/PSFProject/.github/FUNDING.yml
new file mode 100644
index 0000000..4b16f59
--- /dev/null
+++ b/templates/PSFProject/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+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/PSFProject/.github/workflows/build.yml b/templates/PSFProject/.github/workflows/build.yml
new file mode 100644
index 0000000..2bd1de8
--- /dev/null
+++ b/templates/PSFProject/.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 }}
diff --git a/templates/PSFProject/.github/workflows/validate.yml b/templates/PSFProject/.github/workflows/validate.yml
new file mode 100644
index 0000000..64387f3
--- /dev/null
+++ b/templates/PSFProject/.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
diff --git a/templates/PSFProject/PSMDTemplate.ps1 b/templates/PSFProject/PSMDTemplate.ps1
index 05aa08e..37887a9 100644
--- a/templates/PSFProject/PSMDTemplate.ps1
+++ b/templates/PSFProject/PSMDTemplate.ps1
@@ -1,6 +1,6 @@
@{
TemplateName = 'PSFProject'
- Version = "1.3.2.0"
+ Version = "1.3.3"
AutoIncrementVersion = $true
Tags = 'module','psframework'
Author = 'Friedrich Weinmann'
@@ -38,4 +38,5 @@ $null = New-Item -Path "$PSScriptRoot\..\.." -Name TestResults -ItemType Directo
'$config.TestResult.Enabled = $true'
}
}
+ NoFolder = $true
}
\ No newline at end of file
diff --git a/templates/PSFTests/PSMDTemplate.ps1 b/templates/PSFTests/PSMDTemplate.ps1
index 770fb51..7396c33 100644
--- a/templates/PSFTests/PSMDTemplate.ps1
+++ b/templates/PSFTests/PSMDTemplate.ps1
@@ -1,6 +1,6 @@
@{
TemplateName = 'PSFTests' # Insert name of template
- Version = "2.0.0.0" # Version to build to
+ Version = "2.0.1" # Version to build to
AutoIncrementVersion = $true # If a newer version than specified is present, instead of the specified version, make it one greater than the existing template
Tags = @('Tests', 'PSFramework') # Insert Tags as desired
Author = 'Friedrich Weinmann' # The author of the template, not the file / project created from it
diff --git a/templates/PSFTests/general/PSScriptAnalyzer.Tests.ps1 b/templates/PSFTests/general/PSScriptAnalyzer.Tests.ps1
index 74e5a65..a99b60d 100644
--- a/templates/PSFTests/general/PSScriptAnalyzer.Tests.ps1
+++ b/templates/PSFTests/general/PSScriptAnalyzer.Tests.ps1
@@ -12,7 +12,9 @@ if ($SkipTest) { return }
$global:__pester_data.ScriptAnalyzer = New-Object System.Collections.ArrayList
Describe 'Invoking PSScriptAnalyzer against commandbase' {
- $commandFiles = Get-ChildItem -Path $CommandPath -Recurse | Where-Object Name -like "*.ps1"
+ $commandFiles = foreach ($path in $CommandPath) {
+ Get-ChildItem -Path $path -Recurse | Where-Object Name -like "*.ps1"
+ }
$scriptAnalyzerRules = Get-ScriptAnalyzerRule
foreach ($file in $commandFiles)
diff --git a/templates/PSFTests/general/strings.Exceptions.ps1 b/templates/PSFTests/general/strings.Exceptions.ps1
index 0a11c98..b4c91f2 100644
--- a/templates/PSFTests/general/strings.Exceptions.ps1
+++ b/templates/PSFTests/general/strings.Exceptions.ps1
@@ -15,5 +15,22 @@ $exceptions['LegalSurplus'] = @(
$exceptions['LegalSurplus'] = @(
)
+<#
+A list of entries that MAY be used without needing to have text defined.
+This is intended for modules (re-)using strings provided by another module
+#>
+$exceptions['NoTextNeeded'] = @(
+ 'Validate.FSPath'
+ 'Validate.FSPath.File'
+ 'Validate.FSPath.FileOrParent'
+ 'Validate.FSPath.Folder'
+ 'Validate.Path'
+ 'Validate.Path.Container'
+ 'Validate.Path.Leaf'
+ 'Validate.TimeSpan.Positive'
+ 'Validate.Uri.Absolute'
+ 'Validate.Uri.Absolute.File'
+ 'Validate.Uri.Absolute.Https'
+)
$exceptions
\ No newline at end of file
diff --git a/templates/PSFTests/general/strings.Tests.ps1 b/templates/PSFTests/general/strings.Tests.ps1
index 5045dc1..eb83c05 100644
--- a/templates/PSFTests/general/strings.Tests.ps1
+++ b/templates/PSFTests/general/strings.Tests.ps1
@@ -9,17 +9,19 @@
Describe "Testing localization strings" {
- $moduleRoot = (Get-Module þnameþ).ModuleBase
+ $moduleRoot = (Get-Module VHDX).ModuleBase
$stringsResults = Export-PSMDString -ModuleRoot $moduleRoot
$exceptions = & "$global:testroot\general\strings.Exceptions.ps1"
foreach ($stringEntry in $stringsResults) {
if ($stringEntry.String -eq "key") { continue } # Skipping the template default entry
- It "Should be used & have text: $($stringEntry.String)" -TestCases @{ stringEntry = $stringEntry } {
+ It "Should be used & have text: $($stringEntry.String)" -TestCases @{ stringEntry = $stringEntry; exceptions = $exceptions } {
if ($exceptions.LegalSurplus -notcontains $stringEntry.String) {
$stringEntry.Surplus | Should -BeFalse
- }
- $stringEntry.Text | Should -Not -BeNullOrEmpty
+ }
+ if ($exceptions.NoTextNeeded -notcontains $stringEntry.String) {
+ $stringEntry.Text | Should -Not -BeNullOrEmpty
+ }
}
}
}
\ No newline at end of file