diff --git a/.gitattributes b/.gitattributes index d49b050..96c2e0d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,15 @@ # Needed for publishing of examples, build worker defaults to core.autocrlf=input. -* text eol=crlf +* text eol=autocrlf + +*.mof text eol=crlf +*.sh text eol=lf +*.svg eol=lf # Ensure any exe files are treated as binary *.exe binary *.jpg binary *.xl* binary *.pfx binary +*.png binary +*.dll binary +*.so binary diff --git a/.github/ISSUE_TEMPLATE/Problem_with_resource.md b/.github/ISSUE_TEMPLATE/Problem_with_resource.md deleted file mode 100644 index 159e81c..0000000 --- a/.github/ISSUE_TEMPLATE/Problem_with_resource.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: Problem with a resource -about: If you have a problem, bug, or enhancement with a resource in this resource module. ---- - -#### Details of the scenario you tried and the problem that is occurring - -#### Verbose logs showing the problem - -#### Suggested solution to the issue - -#### The DSC configuration that is used to reproduce the issue (as detailed as possible) -```powershell -# insert configuration here -``` - -#### The operating system the target node is running - - -#### Version and build of PowerShell the target node is running - - -#### Version of the DSC module that was used diff --git a/.github/ISSUE_TEMPLATE/Problem_with_resource.yml b/.github/ISSUE_TEMPLATE/Problem_with_resource.yml new file mode 100644 index 0000000..d4dc37c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Problem_with_resource.yml @@ -0,0 +1,87 @@ +name: Problem with a resource +description: If you have a problem, bug, or enhancement with a resource in this resource module. +labels: [] +assignees: [] +body: + - type: markdown + attributes: + value: | + Please prefix the issue title (above) with the resource name, e.g. 'ResourceName: Short description of my issue'! + + Your feedback and support is greatly appreciated, thanks for contributing! + - type: textarea + id: description + attributes: + label: Problem description + description: Details of the scenario you tried and the problem that is occurring. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Verbose logs + description: | + Verbose logs showing the problem. **NOTE! Sensitive information should be obfuscated.** _Will be automatically formatted as plain text._ + placeholder: | + Paste verbose logs here + render: text + validations: + required: true + - type: textarea + id: configuration + attributes: + label: DSC configuration + description: | + The DSC configuration that is used to reproduce the issue (as detailed as possible). **NOTE! Sensitive information should be obfuscated.** _Will be automatically formatted as PowerShell code._ + placeholder: | + Paste DSC configuration here + render: powershell + validations: + required: true + - type: textarea + id: suggestedSolution + attributes: + label: Suggested solution + description: Do you have any suggestions how to solve the issue? + validations: + required: true + - type: textarea + id: targetNodeOS + attributes: + label: Operating system the target node is running + description: | + Please provide as much as possible about the target node, for example edition, version, build, and language. _Will be automatically formatted as plain text._ + + On OS with WMF 5.1 the following command can help get this information: `Get-ComputerInfo -Property @('OsName','OsOperatingSystemSKU','OSArchitecture','WindowsVersion','WindowsBuildLabEx','OsLanguage','OsMuiLanguages')` + placeholder: | + Add operating system information here + render: text + validations: + required: true + - type: textarea + id: targetNodePS + attributes: + label: PowerShell version and build the target node is running + description: | + Please provide the version and build of PowerShell the target node is running. _Will be automatically formatted as plain text._ + + To help with this information, please run this command: `$PSVersionTable` + placeholder: | + Add PowerShell information here + render: text + validations: + required: true + - type: textarea + id: moduleVersion + attributes: + label: xHyper-V version + description: | + Please provide the version of the xHyper-V module that was used. _Will be automatically formatted as plain text._ + + To help with this information, please run this command: `Get-Module -Name 'xHyper-V' -ListAvailable | ft Name,Version,Path` + placeholder: | + Add module information here + render: text + validations: + required: true + diff --git a/.github/ISSUE_TEMPLATE/Resource_proposal.md b/.github/ISSUE_TEMPLATE/Resource_proposal.md deleted file mode 100644 index 9f2a069..0000000 --- a/.github/ISSUE_TEMPLATE/Resource_proposal.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: New resource proposal -about: If you have a new resource proposal that you think should be added to this resource module. ---- - -### Description - -### Proposed properties - -### Special considerations or limitations diff --git a/.github/ISSUE_TEMPLATE/Resource_proposal.yml b/.github/ISSUE_TEMPLATE/Resource_proposal.yml new file mode 100644 index 0000000..2ddd098 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Resource_proposal.yml @@ -0,0 +1,39 @@ +name: New resource proposal +description: If you have a new resource proposal that you think should be added to this resource module. +title: "NewResourceName: New resource proposal" +labels: [] +assignees: [] +body: + - type: markdown + attributes: + value: | + Please replace `NewResourceName` in the issue title (above) with your proposed resource name. + + Thank you for contributing and making this resource module better! + - type: textarea + id: description + attributes: + label: Resource proposal + description: Provide information how this resource will/should work and how it will help users. + validations: + required: true + - type: textarea + id: proposedProperties + attributes: + label: Proposed properties + description: | + List all the proposed properties that the resource should have (key, required, write, and/or read). For each property provide a detailed description, the data type, if a default value should be used, and if the property is limited to a set of values. + value: | + Property | Type qualifier | Data type | Description | Default value | Allowed values + --- | --- | --- | --- | --- | --- + PropertyName | Key | String | Detailed description | None | None + validations: + required: true + - type: textarea + id: considerations + attributes: + label: Special considerations or limitations + description: | + Provide any considerations or limitations you can think of that a contributor should take in account when coding the proposed resource, and or what limitations a user will encounter or should consider when using the proposed resource. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..9917040 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +blank_issues_enabled: false +contact_links: + - name: "Virtual PowerShell User Group #DSC channel" + url: https://dsccommunity.org/community/contact/ + about: "To talk to the community and maintainers of DSC Community, please visit the #DSC channel." + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 73031e9..8c6462e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,50 +1,49 @@ + #### Pull Request (PR) description + #### This Pull Request (PR) fixes the following issues + #### Task list + -- [ ] Added an entry to the change log under the Unreleased section of the - file CHANGELOG.md. Entry should say what was changed and how that - affects users (if applicable), and reference the issue being resolved - (if applicable). + +- [ ] Added an entry to the change log under the Unreleased section of the file CHANGELOG.md. + Entry should say what was changed and how that affects users (if applicable), and + reference the issue being resolved (if applicable). - [ ] Resource documentation added/updated in README.md. -- [ ] Resource parameter descriptions added/updated in README.md, schema.mof - and comment-based help. +- [ ] Resource parameter descriptions added/updated in README.md, schema.mof and comment-based + help. - [ ] Comment-based help added/updated. - [ ] Localization strings added/updated in all localization files as appropriate. - [ ] Examples appropriately added/updated. diff --git a/.gitignore b/.gitignore index 3563fb1..17c483d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,17 @@ output/ + +**.bak +*.local.* +!**/README.md +.kitchen/ + +*.nupkg +*.suo +*.user +*.coverage .vs -.vscode +.psproj +.sln +markdownissues.txt +node_modules +package-lock.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 1bf119a..72f9013 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,13 +7,15 @@ "powershell.codeFormatting.whitespaceAroundOperator": true, "powershell.codeFormatting.whitespaceAfterSeparator": true, "powershell.codeFormatting.ignoreOneLineBlock": false, - "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationAfterEveryPipeline", + "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline", "powershell.codeFormatting.preset": "Custom", "powershell.codeFormatting.alignPropertyValuePairs": true, - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true, + "powershell.developer.bundledModulesPath": "${cwd}/output/RequiredModules", "powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1", "powershell.scriptAnalysis.enable": true, + "files.trimTrailingWhitespace": true, + "files.trimFinalNewlines": true, + "files.insertFinalNewline": true, "files.associations": { "*.ps1xml": "xml" }, @@ -33,7 +35,7 @@ "steppable" ], "[markdown]": { - "files.trimTrailingWhitespace": true, + "files.trimTrailingWhitespace": false, "files.encoding": "utf8" } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4085e3e..2991140 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -41,7 +41,7 @@ "label": "build", "type": "shell", "command": "&${cwd}/build.ps1", - "args": ["-AutoRestore"], + "args": [], "presentation": { "echo": true, "reveal": "always", diff --git a/CHANGELOG.md b/CHANGELOG.md index 24c389b..792e87c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Change log for xHyper-V +# Changelog for xHyper-V The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). @@ -30,6 +30,10 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md) removed from the resource, but in a future release the resource might stop working for Windows Server 2008 R2. +### Changed + +- Update the pipeline files to the lates from Sampler. + ### Fixed - xVMDvdDrive diff --git a/GitVersion.yml b/GitVersion.yml index d6d2a20..d0a78e6 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,25 +1,26 @@ mode: ContinuousDelivery next-version: 3.18.0 -major-version-bump-message: '\s?(breaking|major|breaking\schange)' -minor-version-bump-message: '\s?(add|feature|minor)' +major-version-bump-message: '(breaking\schange|breaking|major)\b' +minor-version-bump-message: '(adds?|features?|minor)\b' patch-version-bump-message: '\s?(fix|patch)' no-bump-message: '\+semver:\s?(none|skip)' -assembly-informational-format: "{NuGetVersionV2}+Sha.{Sha}.Date.{CommitDate}" +assembly-informational-format: '{NuGetVersionV2}+Sha.{Sha}.Date.{CommitDate}' branches: master: tag: preview + regex: ^master$ pull-request: tag: PR feature: tag: useBranchName increment: Minor regex: f(eature(s)?)?[\/-] - source-branches: ["master"] + source-branches: ['master'] hotfix: tag: fix increment: Patch regex: (hot)?fix(es)?[\/-] - source-branches: ["master"] + source-branches: ['master'] ignore: # Ignored these SHA to prevent wrongly raising major version diff --git a/LICENSE b/LICENSE index f4c3ee9..53a72e6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -The MIT License (MIT) +MIT License -Copyright (c) DSC Community contributors. +Copyright (c) DSC Community contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 987765f..09bb4c4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # xHyper-V +This module contains DSC resources for the management and +configuration of Hyper-V hosts, virtual machines and related resources. + [![Build Status](https://dev.azure.com/dsccommunity/xHyper-V/_apis/build/status/dsccommunity.xHyper-V?branchName=master)](https://dev.azure.com/dsccommunity/xHyper-V/_build/latest?definitionId=25&branchName=master) ![Azure DevOps coverage (branch)](https://img.shields.io/azure-devops/coverage/dsccommunity/xHyper-V/25/master) [![codecov](https://codecov.io/gh/dsccommunity/xHyper-V/branch/master/graph/badge.svg)](https://codecov.io/gh/dsccommunity/xHyper-V) @@ -7,9 +10,6 @@ [![PowerShell Gallery (with prereleases)](https://img.shields.io/powershellgallery/vpre/xHyper-V?label=xHyper-V%20Preview)](https://www.powershellgallery.com/packages/xHyper-V/) [![PowerShell Gallery](https://img.shields.io/powershellgallery/v/xHyper-V?label=xHyper-V)](https://www.powershellgallery.com/packages/xHyper-V/) -The **xHyper-V** module contains DSC resources for deployment and configuration -of Hyper-V hosts, virtual machines and related resources. - ## Code of Conduct This project has adopted this [Code of Conduct](CODE_OF_CONDUCT.md). @@ -29,6 +29,19 @@ Please check out common DSC Community [contributing guidelines](https://dsccommu A full list of changes in each version can be found in the [change log](CHANGELOG.md). +## Documentation + +The documentation can be found in the [xHyper-V Wiki](https://github.com/dsccommunity/xHyper-V/wiki). +The DSC resources schema files is used to automatically update the +documentation on each PR merge. + +### Examples + +You can review the [Examples](/source/Examples) directory in the xHyper-V module +for some general use scenarios for all of the resources that are in the module. + +The resource examples are also available in the [xHyper-V Wiki](https://github.com/dsccommunity/xHyper-V/wiki). + ## Resources * [**xVHD**](#xvhd) manages VHDs in a Hyper-V host. diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index de9946e..786c628 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -3,17 +3,18 @@ AddToPath = $true Target = 'output\RequiredModules' Parameters = @{ - Repository = '' + Repository = 'PSGallery' } } InvokeBuild = 'latest' PSScriptAnalyzer = 'latest' - Pester = 'latest' + Pester = '4.10.1' Plaster = 'latest' - ModuleBuilder = '1.0.0' + ModuleBuilder = 'latest' ChangelogManagement = 'latest' Sampler = 'latest' + 'Sampler.GitHubTasks' = 'latest' MarkdownLinkCheck = 'latest' 'DscResource.Test' = 'latest' 'DscResource.AnalyzerRules' = 'latest' @@ -23,4 +24,3 @@ # Build dependent modules 'DscResource.Common' = 'latest' } - diff --git a/Resolve-Dependency.ps1 b/Resolve-Dependency.ps1 index 9541f73..294cb68 100644 --- a/Resolve-Dependency.ps1 +++ b/Resolve-Dependency.ps1 @@ -1,107 +1,183 @@ +<# + .DESCRIPTION + Bootstrap script for PSDepend. + + .PARAMETER DependencyFile + Specifies the configuration file for the this script. The default value is + 'RequiredModules.psd1' relative to this script's path. + + .PARAMETER PSDependTarget + Path for PSDepend to be bootstrapped and save other dependencies. + Can also be CurrentUser or AllUsers if you wish to install the modules in + such scope. The default value is './output/RequiredModules' relative to + this script's path. + + .PARAMETER Proxy + Specifies the URI to use for Proxy when attempting to bootstrap + PackageProvider and PowerShellGet. + + .PARAMETER ProxyCredential + Specifies the credential to contact the Proxy when provided. + + .PARAMETER Scope + Specifies the scope to bootstrap the PackageProvider and PSGet if not available. + THe default value is 'CurrentUser'. + + .PARAMETER Gallery + Specifies the gallery to use when bootstrapping PackageProvider, PSGet and + when calling PSDepend (can be overridden in Dependency files). The default + value is 'PSGallery'. + + .PARAMETER GalleryCredential + Specifies the credentials to use with the Gallery specified above. + + .PARAMETER AllowOldPowerShellGetModule + Allow you to use a locally installed version of PowerShellGet older than + 1.6.0 (not recommended). Default it will install the latest PowerShellGet + if an older version than 2.0 is detected. + + .PARAMETER MinimumPSDependVersion + Allow you to specify a minimum version fo PSDepend, if you're after specific + features. + + .PARAMETER AllowPrerelease + Not yet written. + + .PARAMETER WithYAML + Not yet written. + + .NOTES + Load defaults for parameters values from Resolve-Dependency.psd1 if not + provided as parameter. +#> [CmdletBinding()] param ( [Parameter()] - [String] + [System.String] $DependencyFile = 'RequiredModules.psd1', [Parameter()] - [String] - # Path for PSDepend to be bootstrapped and save other dependencies. - # Can also be CurrentUser or AllUsers if you wish to install the modules in such scope - # Default to $PWD.Path/output/modules - $PSDependTarget = (Join-Path $PSScriptRoot './output/RequiredModules'), + [System.String] + $PSDependTarget = (Join-Path -Path $PSScriptRoot -ChildPath './output/RequiredModules'), [Parameter()] - [uri] - # URI to use for Proxy when attempting to Bootstrap PackageProvider & PowerShellGet + [System.Uri] $Proxy, [Parameter()] - # Credential to contact the Proxy when provided - [PSCredential]$ProxyCredential, + [System.Management.Automation.PSCredential] + $ProxyCredential, [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] - [String] - # Scope to bootstrap the PackageProvider and PSGet if not available + [System.String] $Scope = 'CurrentUser', [Parameter()] - [String] - # Gallery to use when bootstrapping PackageProvider, PSGet and when calling PSDepend (can be overridden in Dependency files) + [System.String] $Gallery = 'PSGallery', [Parameter()] - [PSCredential] - # Credentials to use with the Gallery specified above + [System.Management.Automation.PSCredential] $GalleryCredential, - [Parameter()] - [switch] - # Allow you to use a locally installed version of PowerShellGet older than 1.6.0 (not recommended, default to $False) + [System.Management.Automation.SwitchParameter] $AllowOldPowerShellGetModule, [Parameter()] - [String] - # Allow you to specify a minimum version fo PSDepend, if you're after specific features. + [System.String] $MinimumPSDependVersion, [Parameter()] - [Switch] + [System.Management.Automation.SwitchParameter] $AllowPrerelease, [Parameter()] - [Switch] + [System.Management.Automation.SwitchParameter] $WithYAML ) -# Load Defaults for parameters values from Resolve-Dependency.psd1 if not provided as parameter try { - Write-Verbose -Message "Importing Bootstrap default parameters from '$PSScriptRoot/Resolve-Dependency.psd1'." - $ResolveDependencyDefaults = Import-PowerShellDataFile -Path (Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1' -Resolve -ErrorAction Stop) - $ParameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys - if ($ParameterToDefault.Count -eq 0) + if ($PSVersionTable.PSVersion.Major -le 5) + { + if (-not (Get-Command -Name 'Import-PowerShellDataFile' -ErrorAction 'SilentlyContinue')) + { + Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion '3.1.0.0' + } + + <# + Making sure the imported PackageManagement module is not from PS7 module + path. The VSCode PS extension is changing the $env:PSModulePath and + prioritize the PS7 path. This is an issue with PowerShellGet because + it loads an old version if available (or fail to load latest). + #> + Get-Module -ListAvailable PackageManagement | + Where-Object -Property 'ModuleBase' -NotMatch 'powershell.7' | + Select-Object -First 1 | + Import-Module -Force + } + + Write-Verbose -Message 'Importing Bootstrap default parameters from ''$PSScriptRoot/Resolve-Dependency.psd1''.' + + $resolveDependencyConfigPath = Join-Path -Path $PSScriptRoot -ChildPath '.\Resolve-Dependency.psd1' -Resolve -ErrorAction 'Stop' + + $resolveDependencyDefaults = Import-PowerShellDataFile -Path $resolveDependencyConfigPath + + $parameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys + + if ($parameterToDefault.Count -eq 0) { - $ParameterToDefault = $MyInvocation.MyCommand.Parameters.Keys + $parameterToDefault = $MyInvocation.MyCommand.Parameters.Keys } - # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option - foreach ($ParamName in $ParameterToDefault) + + # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option. + foreach ($parameterName in $parameterToDefault) { - if (-Not $PSBoundParameters.Keys.Contains($ParamName) -and $ResolveDependencyDefaults.ContainsKey($ParamName)) + if (-not $PSBoundParameters.Keys.Contains($parameterName) -and $resolveDependencyDefaults.ContainsKey($parameterName)) { - Write-Verbose -Message "Setting $ParamName with $($ResolveDependencyDefaults[$ParamName])" + Write-Verbose -Message "Setting $parameterName with $($resolveDependencyDefaults[$parameterName])." + try { - $variableValue = $ResolveDependencyDefaults[$ParamName] - if ($variableValue -is [string]) + $variableValue = $resolveDependencyDefaults[$parameterName] + + if ($variableValue -is [System.String]) { $variableValue = $ExecutionContext.InvokeCommand.ExpandString($variableValue) } - $PSBoundParameters.Add($ParamName, $variableValue) - Set-Variable -Name $ParamName -value $variableValue -Force -ErrorAction SilentlyContinue + + $PSBoundParameters.Add($parameterName, $variableValue) + + Set-Variable -Name $parameterName -value $variableValue -Force -ErrorAction 'SilentlyContinue' } catch { - Write-Verbose -Message "Error adding default for $ParamName : $($_.Exception.Message)" + Write-Verbose -Message "Error adding default for $parameterName : $($_.Exception.Message)." } } } } catch { - Write-Warning -Message "Error attempting to import Bootstrap's default parameters from $(Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1'): $($_.Exception.Message)." + Write-Warning -Message "Error attempting to import Bootstrap's default parameters from '$resolveDependencyConfigPath': $($_.Exception.Message)." } -Write-Progress -Activity "Bootstrap:" -PercentComplete 0 -CurrentOperation "NuGet Bootstrap" +Write-Progress -Activity 'Bootstrap:' -PercentComplete 0 -CurrentOperation 'NuGet Bootstrap' -if (!(Get-PackageProvider -Name NuGet -ForceBootstrap -ErrorAction SilentlyContinue)) +# TODO: This should handle the parameter $AllowOldPowerShellGetModule. +$powerShellGetModule = Import-Module -Name 'PowerShellGet' -MinimumVersion '2.0' -ErrorAction 'SilentlyContinue' -PassThru + +# Install the package provider if it is not available. +$nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 + +if (-not $powerShellGetModule -and -not $nuGetProvider) { - $providerBootstrapParams = @{ + $providerBootstrapParameters = @{ Name = 'nuget' - force = $true + Force = $true ForceBootstrap = $true ErrorAction = 'Stop' } @@ -110,47 +186,60 @@ if (!(Get-PackageProvider -Name NuGet -ForceBootstrap -ErrorAction SilentlyConti { 'Proxy' { - $providerBootstrapParams.Add('Proxy', $Proxy) + $providerBootstrapParameters.Add('Proxy', $Proxy) } + 'ProxyCredential' { - $providerBootstrapParams.Add('ProxyCredential', $ProxyCredential) + $providerBootstrapParameters.Add('ProxyCredential', $ProxyCredential) } + 'Scope' { - $providerBootstrapParams.Add('Scope', $Scope) + $providerBootstrapParameters.Add('Scope', $Scope) } } if ($AllowPrerelease) { - $providerBootstrapParams.Add('AllowPrerelease', $true) + $providerBootstrapParameters.Add('AllowPrerelease', $true) } - Write-Information "Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed)" + Write-Information -MessageData 'Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed).' + $null = Install-PackageProvider @providerBootstrapParams - $latestNuGetVersion = (Get-PackageProvider -Name NuGet -ListAvailable | Select-Object -First 1).Version.ToString() - Write-Information "Bootstrap: Importing NuGet Package Provider version $latestNuGetVersion to current session." - $Null = Import-PackageProvider -Name NuGet -RequiredVersion $latestNuGetVersion -Force + + $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 + + $nuGetProviderVersion = $nuGetProvider.Version.ToString() + + Write-Information -MessageData "Bootstrap: Importing NuGet Package Provider version $nuGetProviderVersion to current session." + + $Null = Import-PackageProvider -Name 'NuGet' -RequiredVersion $nuGetProviderVersion -Force } -Write-Progress -Activity "Bootstrap:" -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" +Write-Progress -Activity 'Bootstrap:' -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" + +# Fail if the given PSGallery is not registered. +$previousGalleryInstallationPolicy = (Get-PSRepository -Name $Gallery -ErrorAction 'Stop').InstallationPolicy + +Set-PSRepository -Name $Gallery -InstallationPolicy 'Trusted' -ErrorAction 'Ignore' -# Fail if the given PSGallery is not Registered -$Policy = (Get-PSRepository $Gallery -ErrorAction Stop).InstallationPolicy -Set-PSRepository -Name $Gallery -InstallationPolicy Trusted -ErrorAction Ignore try { - Write-Progress -Activity "Bootstrap:" -PercentComplete 25 -CurrentOperation "Checking PowerShellGet" - # Ensure the module is loaded and retrieve the version you have - $PowerShellGetVersion = (Import-Module PowerShellGet -PassThru -ErrorAction SilentlyContinue).Version + Write-Progress -Activity 'Bootstrap:' -PercentComplete 25 -CurrentOperation 'Checking PowerShellGet' + + # Ensure the module is loaded and retrieve the version you have. + $powerShellGetVersion = (Import-Module -Name 'PowerShellGet' -PassThru -ErrorAction 'SilentlyContinue').Version - Write-Verbose "Bootstrap: The PowerShellGet version is $PowerShellGetVersion" - # Versions below 1.6.0 are considered old, unreliable & not recommended - if (!$PowerShellGetVersion -or ($PowerShellGetVersion -lt [System.version]'1.6.0' -and !$AllowOldPowerShellGetModule)) + Write-Verbose -Message "Bootstrap: The PowerShellGet version is $powerShellGetVersion" + + # Versions below 2.0 are considered old, unreliable & not recommended + if (-not $powerShellGetVersion -or ($powerShellGetVersion -lt [System.Version] '2.0' -and -not $AllowOldPowerShellGetModule)) { - Write-Progress -Activity "Bootstrap:" -PercentComplete 40 -CurrentOperation "Installing newer version of PowerShellGet" - $InstallPSGetParam = @{ + Write-Progress -Activity 'Bootstrap:' -PercentComplete 40 -CurrentOperation 'Installing newer version of PowerShellGet' + + $installPowerShellGetParameters = @{ Name = 'PowerShellGet' Force = $True SkipPublisherCheck = $true @@ -163,49 +252,64 @@ try { 'Proxy' { - $InstallPSGetParam.Add('Proxy', $Proxy) + $installPowerShellGetParameters.Add('Proxy', $Proxy) } + 'ProxyCredential' { - $InstallPSGetParam.Add('ProxyCredential', $ProxyCredential) + $installPowerShellGetParameters.Add('ProxyCredential', $ProxyCredential) } + 'GalleryCredential' { - $InstallPSGetParam.Add('Credential', $GalleryCredential) + $installPowerShellGetParameters.Add('Credential', $GalleryCredential) } } - Install-Module @InstallPSGetParam - Remove-Module PowerShellGet -force -ErrorAction SilentlyContinue - Import-Module PowerShellGet -Force - $NewLoadedVersion = (Get-Module PowerShellGet).Version.ToString() - Write-Information "Bootstrap: PowerShellGet version loaded is $NewLoadedVersion" - Write-Progress -Activity "Bootstrap:" -PercentComplete 60 -CurrentOperation "Installing newer version of PowerShellGet" + Write-Progress -Activity 'Bootstrap:' -PercentComplete 60 -CurrentOperation 'Installing newer version of PowerShellGet' + + Install-Module @installPowerShellGetParameters + + Remove-Module -Name 'PowerShellGet' -Force -ErrorAction 'SilentlyContinue' + Remove-Module -Name 'PackageManagement' -Force + + $powerShellGetModule = Import-Module PowerShellGet -Force -PassThru + + $powerShellGetVersion = $powerShellGetModule.Version.ToString() + + Write-Information -MessageData "Bootstrap: PowerShellGet version loaded is $powerShellGetVersion" + } + + # Try to import the PSDepend module from the available modules. + $getModuleParameters = @{ + Name = 'PSDepend' + ListAvailable = $true } - # Try to import the PSDepend module from the available modules - try + $psDependModule = Get-Module @getModuleParameters + + if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { - $ImportPSDependParam = @{ - Name = 'PSDepend' - ErrorAction = 'Stop' - Force = $true + try + { + $psDependModule = $psDependModule | Where-Object -FilterScript { $_.Version -ge $MinimumPSDependVersion } } - - if ($MinimumPSDependVersion) + catch { - $ImportPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) + throw ('There was a problem finding the minimum version of PSDepend. Error: {0}' -f $_) } - $null = Import-Module @ImportPSDependParam } - catch + + if (-not $psDependModule) { - # PSDepend module not found, installing or saving it + # PSDepend module not found, installing or saving it. if ($PSDependTarget -in 'CurrentUser', 'AllUsers') { - Write-Debug "PSDepend module not found. Attempting to install from Gallery $Gallery" - Write-Warning "Installing PSDepend in $PSDependTarget Scope" - $InstallPSDependParam = @{ + Write-Debug -Message "PSDepend module not found. Attempting to install from Gallery $Gallery." + + Write-Warning -Message "Installing PSDepend in $PSDependTarget Scope." + + $installPSDependParameters = @{ Name = 'PSDepend' Repository = $Gallery Force = $true @@ -216,50 +320,69 @@ try if ($MinimumPSDependVersion) { - $InstallPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) + $installPSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) } - Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" - Install-Module @InstallPSDependParam + Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" + + Install-Module @installPSDependParameters } else { - Write-Debug "PSDepend module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" - $SaveModuleParam = @{ + Write-Debug -Message "PSDepend module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" + + $saveModuleParameters = @{ Name = 'PSDepend' Repository = $Gallery Path = $PSDependTarget + Force = $true } if ($MinimumPSDependVersion) { - $SaveModuleParam.add('MinimumVersion', $MinimumPSDependVersion) + $saveModuleParameters.add('MinimumVersion', $MinimumPSDependVersion) } - Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Saving & Importing PSDepend from $Gallery to $Scope" - Save-Module @SaveModuleParam + Write-Progress -Activity 'Bootstrap:' -PercentComplete 75 -CurrentOperation "Saving & Importing PSDepend from $Gallery to $Scope" + + Save-Module @saveModuleParameters } } - finally + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 80 -CurrentOperation 'Loading PSDepend' + + $importModulePSDependParameters = @{ + Name = 'PSDepend' + ErrorAction = 'Stop' + Force = $true + } + + if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { - Write-Progress -Activity "Bootstrap:" -PercentComplete 100 -CurrentOperation "Loading PSDepend" - # We should have successfully bootstrapped PSDepend. Fail if not available - Import-Module PSDepend -ErrorAction Stop + $importModulePSDependParameters.Add('MinimumVersion', $MinimumPSDependVersion) } + # We should have successfully bootstrapped PSDepend. Fail if not available. + $null = Import-Module @importModulePSDependParameters + if ($WithYAML) { - if (-Not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) + Write-Progress -Activity 'Bootstrap:' -PercentComplete 82 -CurrentOperation 'Verifying PowerShell module PowerShell-Yaml' + + if (-not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) { - Write-Verbose "PowerShell-Yaml module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" + Write-Progress -Activity 'Bootstrap:' -PercentComplete 85 -CurrentOperation 'Installing PowerShell module PowerShell-Yaml' + + Write-Verbose -Message "PowerShell-Yaml module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" + $SaveModuleParam = @{ Name = 'PowerShell-Yaml' Repository = $Gallery Path = $PSDependTarget + Force = $true } Save-Module @SaveModuleParam - Import-Module "PowerShell-Yaml" -ErrorAction Stop } else { @@ -267,22 +390,28 @@ try } } + Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoke PSDepend' + Write-Progress -Activity "PSDepend:" -PercentComplete 0 -CurrentOperation "Restoring Build Dependencies" - if (Test-Path $DependencyFile) + + if (Test-Path -Path $DependencyFile) { - $PSDependParams = @{ + $psDependParameters = @{ Force = $true Path = $DependencyFile } - # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified - Invoke-PSDepend @PSDependParams + # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified. + Invoke-PSDepend @psDependParameters } + Write-Progress -Activity "PSDepend:" -PercentComplete 100 -CurrentOperation "Dependencies restored" -Completed + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 100 -CurrentOperation "Bootstrap complete" -Completed } finally { # Reverting the Installation Policy for the given gallery - Set-PSRepository -Name $Gallery -InstallationPolicy $Policy - Write-Verbose "Project Bootstrapped, returning to Invoke-Build" + Set-PSRepository -Name $Gallery -InstallationPolicy $previousGalleryInstallationPolicy + Write-Verbose -Message "Project Bootstrapped, returning to Invoke-Build" } diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7bd7bc2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +## Security + +The DSC Community takes the security of our modules seriously, which includes all source code repositories managed through our GitHub organization. + +If you believe you have found a security vulnerability in any DSC Community owned repository, please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to one or several members of the DSC Community organization. +The easiest way to do so is to send us a direct message via twitter or slack. + +You should receive a response within 48 hours. If for some reason you do not, please follow up to other member of the community. + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Preferred Languages + +We prefer all communications to be in English. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3dc0fe1..a32e02c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,18 +3,21 @@ trigger: include: - master paths: - exclude: - - CHANGELOG.md + include: + - source/* tags: include: - "v*" exclude: - "*-*" + variables: buildFolderName: output buildArtifactName: output testResultFolderName: testResults testArtifactName: testResults + sourceFolderName: source + defaultBranch: master stages: - stage: Build @@ -22,14 +25,17 @@ stages: - job: Package_Module displayName: 'Package Module' pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' steps: - - task: GitVersion@5 - name: gitVersion - displayName: 'Evaluate Next Version' - inputs: - runtime: 'core' - configFilePath: 'GitVersion.yml' + - pwsh: | + dotnet tool install --global GitVersion.Tool + $gitVersionObject = dotnet-gitversion | ConvertFrom-Json + $gitVersionObject.PSObject.Properties.ForEach{ + Write-Host -Object "Setting Task Variable '$($_.Name)' with value '$($_.Value)'." + Write-Host -Object "##vso[task.setvariable variable=$($_.Name);]$($_.Value)" + } + Write-Host -Object "##vso[build.updatebuildnumber]$($gitVersionObject.FullSemVer)" + displayName: Calculate ModuleVersion (GitVersion) - task: PowerShell@2 name: package displayName: 'Build & Package Module' @@ -38,13 +44,14 @@ stages: arguments: '-ResolveDependency -tasks pack' pwsh: true env: - ModuleVersion: $(gitVersion.InformationalVersion) - - task: PublishBuildArtifacts@1 + ModuleVersion: $(NuGetVersionV2) + - task: PublishPipelineArtifact@1 displayName: 'Publish Build Artifact' inputs: - pathToPublish: '$(buildFolderName)/' - artifactName: $(buildArtifactName) - publishLocation: 'Container' + targetPath: '$(buildFolderName)/' + artifact: $(buildArtifactName) + publishLocation: 'pipeline' + parallel: true - stage: Test dependsOn: Build @@ -52,16 +59,15 @@ stages: - job: Test_HQRM displayName: 'HQRM' pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' timeoutInMinutes: 0 steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run HQRM Test' @@ -80,16 +86,15 @@ stages: - job: Test_Unit displayName: 'Unit' pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' timeoutInMinutes: 0 steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' artifactName: $(buildArtifactName) - downloadPath: '$(Build.SourcesDirectory)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Unit Test' @@ -103,27 +108,26 @@ stages: inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' - testRunTitle: 'Unit (Windows Server Core)' - - task: PublishBuildArtifacts@1 + testRunTitle: 'Unit' + - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' inputs: - pathToPublish: '$(buildFolderName)/$(testResultFolderName)/' + targetPath: '$(buildFolderName)/$(testResultFolderName)/' artifactName: $(testArtifactName) - publishLocation: 'Container' + parallel: true - job: Test_Integration displayName: 'Integration' pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' timeoutInMinutes: 0 steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' artifactName: $(buildArtifactName) - downloadPath: '$(Build.SourcesDirectory)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: configureWinRM displayName: 'Configure WinRM' @@ -136,7 +140,7 @@ stages: displayName: 'Run Integration Test' inputs: filePath: './build.ps1' - arguments: "-Tasks test -PesterScript 'tests/Integration' -CodeCoverageThreshold 0" + arguments: "-Tasks test -CodeCoverageThreshold 0 -PesterScript 'tests/Integration'" pwsh: false - task: PublishTestResults@2 displayName: 'Publish Test Results' @@ -144,45 +148,37 @@ stages: inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' - testRunTitle: 'Integration (Windows Server Core)' + testRunTitle: 'Integration' - job: Code_Coverage displayName: 'Publish Code Coverage' dependsOn: Test_Unit pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' timeoutInMinutes: 0 steps: - - pwsh: | - $repositoryOwner,$repositoryName = $env:BUILD_REPOSITORY_NAME -split '/' - echo "##vso[task.setvariable variable=RepositoryOwner;isOutput=true]$repositoryOwner" - echo "##vso[task.setvariable variable=RepositoryName;isOutput=true]$repositoryName" - name: dscBuildVariable - displayName: 'Set Environment Variables' - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' artifactName: $(buildArtifactName) - downloadPath: '$(Build.SourcesDirectory)' - - task: DownloadBuildArtifacts@0 + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + - task: DownloadPipelineArtifact@2 displayName: 'Download Test Artifact' inputs: buildType: 'current' - downloadType: 'single' artifactName: $(testArtifactName) - downloadPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' - task: PublishCodeCoverageResults@1 - displayName: 'Publish Azure Code Coverage' + displayName: 'Publish Code Coverage to Azure DevOps' condition: succeededOrFailed() inputs: codeCoverageTool: 'JaCoCo' - summaryFileLocation: '$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml' - pathToSources: '$(Build.SourcesDirectory)/$(buildFolderName)/$(dscBuildVariable.RepositoryName)' + summaryFileLocation: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml' + pathToSources: '$(Build.SourcesDirectory)/$(sourceFolderName)/' - script: | bash <(curl -s https://codecov.io/bash) -f "./$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml" - displayName: 'Upload to Codecov.io' + displayName: 'Publish Code Coverage to Codecov.io' condition: succeededOrFailed() - stage: Deploy @@ -200,15 +196,14 @@ stages: - job: Deploy_Module displayName: 'Deploy Module' pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifact' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Pipeline Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildArtifactName)' - task: PowerShell@2 name: publishRelease displayName: 'Publish Release' @@ -219,6 +214,8 @@ stages: env: GitHubToken: $(GitHubToken) GalleryApiToken: $(GalleryApiToken) + ReleaseBranch: $(defaultBranch) + MainGitBranch: $(defaultBranch) - task: PowerShell@2 name: sendChangelogPR displayName: 'Send Changelog PR' @@ -228,3 +225,5 @@ stages: pwsh: true env: GitHubToken: $(GitHubToken) + ReleaseBranch: $(defaultBranch) + MainGitBranch: $(defaultBranch) diff --git a/build.ps1 b/build.ps1 index f236bab..5579df1 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,240 +1,359 @@ <# .DESCRIPTION - Bootstrap and build script for PowerShell module pipeline + Bootstrap and build script for PowerShell module CI/CD pipeline + + .PARAMETER Tasks + The task or tasks to run. The default value is '.' (runs the default task). + + .PARAMETER CodeCoverageThreshold + The code coverage target threshold to uphold. Set to 0 to disable. + The default value is '' (empty string). + + .PARAMETER BuildConfig + Not yet written. + + .PARAMETER OutputDirectory + Specifies the folder to build the artefact into. The default value is 'output'. + + .PARAMETER BuiltModuleSubdirectory + Subdirectory name to build the module (under $OutputDirectory). The default + value is '' (empty string). + + .PARAMETER RequiredModulesDirectory + Can be a path (relative to $PSScriptRoot or absolute) to tell Resolve-Dependency + and PSDepend where to save the required modules. It is also possible to use + 'CurrentUser' och 'AllUsers' to install missing dependencies. You can override + the value for PSDepend in the Build.psd1 build manifest. The default value is + 'output/RequiredModules'. + + .PARAMETER PesterScript + One or more paths that will override the Pester configuration in build + configuration file when running the build task Invoke_Pester_Tests. + + If running Pester 5 test, use the alias PesterPath to be future-proof. + + .PARAMETER PesterTag + Filter which tags to run when invoking Pester tests. This is used in the + Invoke-Pester.pester.build.ps1 tasks. + + .PARAMETER PesterExcludeTag + Filter which tags to exclude when invoking Pester tests. This is used in + the Invoke-Pester.pester.build.ps1 tasks. + + .PARAMETER DscTestTag + Filter which tags to run when invoking DSC Resource tests. This is used + in the DscResource.Test.build.ps1 tasks. + + .PARAMETER DscTestExcludeTag + Filter which tags to exclude when invoking DSC Resource tests. This is + used in the DscResource.Test.build.ps1 tasks. + + .PARAMETER ResolveDependency + Not yet written. + + .PARAMETER BuildInfo + The build info object from ModuleBuilder. Defaults to an empty hashtable. + + .PARAMETER AutoRestore + Not yet written. #> [CmdletBinding()] param ( [Parameter(Position = 0)] - [string[]] + [System.String[]] $Tasks = '.', [Parameter()] - [String] + [System.String] $CodeCoverageThreshold = '', [Parameter()] - [validateScript( + [System.String] + [ValidateScript( { Test-Path -Path $_ } )] $BuildConfig, [Parameter()] - # A Specific folder to build the artefact into. + [System.String] $OutputDirectory = 'output', [Parameter()] - # Subdirectory name to build the module (under $OutputDirectory) + [System.String] $BuiltModuleSubdirectory = '', - # Can be a path (relative to $PSScriptRoot or absolute) to tell Resolve-Dependency & PSDepend where to save the required modules, - # or use CurrentUser, AllUsers to target where to install missing dependencies - # You can override the value for PSDepend in the Build.psd1 build manifest - # This defaults to $OutputDirectory/modules (by default: ./output/modules) [Parameter()] + [System.String] $RequiredModulesDirectory = $(Join-Path 'output' 'RequiredModules'), [Parameter()] - [object[]] + # This alias is to prepare for the rename of this parameter to PesterPath when Pester 4 support is removed + [Alias('PesterPath')] + [System.Object[]] $PesterScript, - # Filter which tags to run when invoking Pester tests - # This is used in the Invoke-Pester.pester.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $PesterTag, - # Filter which tags to exclude when invoking Pester tests - # This is used in the Invoke-Pester.pester.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $PesterExcludeTag, - # Filter which tags to run when invoking DSC Resource tests - # This is used in the DscResource.Test.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $DscTestTag, - # Filter which tags to exclude when invoking DSC Resource tests - # This is used in the DscResource.Test.build.ps1 tasks [Parameter()] - [string[]] + [System.String[]] $DscTestExcludeTag, [Parameter()] [Alias('bootstrap')] - [switch]$ResolveDependency, + [System.Management.Automation.SwitchParameter] + $ResolveDependency, [Parameter(DontShow)] [AllowNull()] + [System.Collections.Hashtable] $BuildInfo, [Parameter()] - [switch] + [System.Management.Automation.SwitchParameter] $AutoRestore ) -# The BEGIN block (at the end of this file) handles the Bootstrap of the Environment before Invoke-Build can run the tasks -# if the -ResolveDependency (aka Bootstrap) is specified, the modules are already available, and can be auto loaded +<# + The BEGIN block (at the end of this file) handles the Bootstrap of the Environment + before Invoke-Build can run the tasks if the parameter ResolveDependency (or + parameter alias Bootstrap) is specified. +#> process { if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') { - # Only run the process block through InvokeBuild (Look at the Begin block at the bottom of this script) + # Only run the process block through InvokeBuild (look at the Begin block at the bottom of this script). return } - # Execute the Build Process from the .build.ps1 path. - Push-Location -Path $PSScriptRoot -StackName BeforeBuild + # Execute the Build process from the .build.ps1 path. + Push-Location -Path $PSScriptRoot -StackName 'BeforeBuild' try { - Write-Host -ForeGroundColor magenta "[build] Parsing defined tasks" + Write-Host -Object "[build] Parsing defined tasks" -ForeGroundColor Magenta - # Load Default BuildInfo if not provided as parameter - if (!$PSBoundParameters.ContainsKey('BuildInfo')) + # Load the default BuildInfo if the parameter BuildInfo is not set. + if (-not $PSBoundParameters.ContainsKey('BuildInfo')) { try { - if (Test-Path $BuildConfig) + if (Test-Path -Path $BuildConfig) { - $ConfigFile = (Get-Item -Path $BuildConfig) - Write-Host "[build] Loading Configuration from $ConfigFile" - $BuildInfo = switch -Regex ($ConfigFile.Extension) + $configFile = Get-Item -Path $BuildConfig + + Write-Host -Object "[build] Loading Configuration from $configFile" + + $BuildInfo = switch -Regex ($configFile.Extension) { # Native Support for PSD1 '\.psd1' { + if (-not (Get-Command -Name Import-PowerShellDataFile -ErrorAction SilentlyContinue)) + { + Import-Module -Name Microsoft.PowerShell.Utility -RequiredVersion 3.1.0.0 + } + Import-PowerShellDataFile -Path $BuildConfig } + # Support for yaml when module PowerShell-Yaml is available '\.[yaml|yml]' { - Import-Module -ErrorAction Stop -Name 'powershell-yaml' - ConvertFrom-Yaml -Yaml (Get-Content -Raw $ConfigFile) + Import-Module -Name 'powershell-yaml' -ErrorAction Stop + + ConvertFrom-Yaml -Yaml (Get-Content -Raw $configFile) } + # Native Support for JSON and JSONC (by Removing comments) '\.[json|jsonc]' { - $JSONC = (Get-Content -Raw -Path $ConfigFile) - $JSON = $JSONC -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/' - # This should probably be converted to hashtable for splatting - $JSON | ConvertFrom-Json + $jsonFile = Get-Content -Raw -Path $configFile + + $jsonContent = $jsonFile -replace '(?m)\s*//.*?$' -replace '(?ms)/\*.*?\*/' + + # Yaml is superset of JSON. + ConvertFrom-Yaml -Yaml $jsonContent } + + # Unknown extension, return empty hashtable. default { - Write-Error "Extension '$_' not supported. using @{}" + Write-Error -Message "Extension '$_' not supported. using @{}" + @{ } } } } else { - Write-Host -Object "Configuration file $BuildConfig not found" -ForegroundColor Red + Write-Host -Object "Configuration file '$($BuildConfig.FullName)' not found" -ForegroundColor Red + + # No config file was found, return empty hashtable. $BuildInfo = @{ } } } catch { - Write-Host -Object "Error loading Config $ConfigFile.`r`n Are you missing dependencies?" -ForegroundColor Yellow - Write-Host -Object "Make sure you run './build.ps1 -ResolveDependency -tasks noop' to restore the Required modules the first time" -ForegroundColor Yellow + $logMessage = "Error loading Config '$($BuildConfig.FullName)'.`r`nAre you missing dependencies?`r`nMake sure you run './build.ps1 -ResolveDependency -tasks noop' before running build to restore the required modules." + + Write-Host -Object $logMessage -ForegroundColor Yellow + $BuildInfo = @{ } - Write-Error $_.Exception.Message + + Write-Error -Message $_.Exception.Message } } - # If the Invoke-Build Task Header is specified in the Build Info, set it + # If the Invoke-Build Task Header is specified in the Build Info, set it. if ($BuildInfo.TaskHeader) { - Set-BuildHeader ([scriptblock]::Create($BuildInfo.TaskHeader)) + Set-BuildHeader -Script ([scriptblock]::Create($BuildInfo.TaskHeader)) + } + + <# + Add BuildModuleOutput to PSModule Path environment variable. + Moved here (not in begin block) because build file can contains BuiltSubModuleDirectory value. + #> + if ($BuiltModuleSubdirectory) + { + if (-not (Split-Path -IsAbsolute -Path $BuiltModuleSubdirectory)) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuiltModuleSubdirectory + } + else + { + $BuildModuleOutput = $BuiltModuleSubdirectory + } + } # test if BuiltModuleSubDirectory set in build config file + elseif ($BuildInfo.ContainsKey('BuiltModuleSubDirectory')) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuildInfo['BuiltModuleSubdirectory'] + } + else + { + $BuildModuleOutput = $OutputDirectory } - # Import Tasks from modules via their exported aliases when defined in BUild Manifest - # https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks - if ($BuildInfo.containsKey('ModuleBuildTasks')) + # Pre-pending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder. + if ($powerShellModulePaths -notcontains $BuildModuleOutput) { - foreach ($Module in $BuildInfo['ModuleBuildTasks'].Keys) + Write-Host -Object "[build] Pre-pending '$BuildModuleOutput' folder to PSModulePath" -ForegroundColor Green + + $env:PSModulePath = $BuildModuleOutput + [System.IO.Path]::PathSeparator + $env:PSModulePath + } + + <# + Import Tasks from modules via their exported aliases when defined in Build Manifest. + https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks + #> + if ($BuildInfo.ContainsKey('ModuleBuildTasks')) + { + foreach ($module in $BuildInfo['ModuleBuildTasks'].Keys) { try { - Write-Host -ForegroundColor DarkGray -Verbose "Importing tasks from module $Module" - $LoadedModule = Import-Module $Module -PassThru -ErrorAction Stop - foreach ($TaskToExport in $BuildInfo['ModuleBuildTasks'].($Module)) + Write-Host -Object "Importing tasks from module $module" -ForegroundColor DarkGray + + $loadedModule = Import-Module -Name $module -PassThru -ErrorAction Stop + + foreach ($TaskToExport in $BuildInfo['ModuleBuildTasks'].($module)) { - $LoadedModule.ExportedAliases.GetEnumerator().Where{ - # using -like to support wildcard - Write-Host -ForegroundColor DarkGray "`t Loading $($_.Key)..." + $loadedModule.ExportedAliases.GetEnumerator().Where{ + Write-Host -Object "`t Loading $($_.Key)..." -ForegroundColor DarkGray + + # Using -like to support wildcard. $_.Key -like $TaskToExport }.ForEach{ - # Dot sourcing the Tasks via their exported aliases + # Dot-sourcing the Tasks via their exported aliases. . (Get-Alias $_.Key) } } } catch { - Write-Host -ForegroundColor Red -Object "Could not load tasks for module $Module." - Write-Error $_ + Write-Host -Object "Could not load tasks for module $module." -ForegroundColor Red + + Write-Error -Message $_ } } } - # Loading Build Tasks defined in the .build/ folder (will override the ones imported above if same task name) - Get-ChildItem -Path ".build/" -Recurse -Include *.ps1 -ErrorAction Ignore | ForEach-Object { - "Importing file $($_.BaseName)" | Write-Verbose - . $_.FullName - } + # Loading Build Tasks defined in the .build/ folder (will override the ones imported above if same task name). + Get-ChildItem -Path '.build/' -Recurse -Include '*.ps1' -ErrorAction Ignore | + ForEach-Object { + "Importing file $($_.BaseName)" | Write-Verbose - # Synopsis: Empty task, useful to test the bootstrap process + . $_.FullName + } + + # Synopsis: Empty task, useful to test the bootstrap process. task noop { } - # Define default task sequence ("."), can be overridden in the $BuildInfo + # Define default task sequence ("."), can be overridden in the $BuildInfo. task . { - Write-Build Yellow "No sequence currently defined for the default task" + Write-Build -Object 'No sequence currently defined for the default task' -ForegroundColor Yellow } - # Load Invoke-Build task sequences/workflows from $BuildInfo - Write-Host -ForegroundColor DarkGray "Adding Workflow from configuration:" - foreach ($Workflow in $BuildInfo.BuildWorkflow.keys) + Write-Host -Object 'Adding Workflow from configuration:' -ForegroundColor DarkGray + + # Load Invoke-Build task sequences/workflows from $BuildInfo. + foreach ($workflow in $BuildInfo.BuildWorkflow.keys) { - Write-Verbose "Creating Build Workflow '$Workflow' with tasks $($BuildInfo.BuildWorkflow.($Workflow) -join ', ')" - $WorkflowItem = $BuildInfo.BuildWorkflow.($Workflow) - if ($WorkflowItem.Trim() -match '^\{(?[\w\W]*)\}$') + Write-Verbose -Message "Creating Build Workflow '$Workflow' with tasks $($BuildInfo.BuildWorkflow.($Workflow) -join ', ')." + + $workflowItem = $BuildInfo.BuildWorkflow.($workflow) + + if ($workflowItem.Trim() -match '^\{(?[\w\W]*)\}$') { - $WorkflowItem = [ScriptBlock]::Create($Matches['sb']) + $workflowItem = [ScriptBlock]::Create($Matches['sb']) } - Write-Host -ForegroundColor DarkGray " +-> $Workflow" - task $Workflow $WorkflowItem + + Write-Host -Object " +-> $workflow" -ForegroundColor DarkGray + + task $workflow $workflowItem } - Write-Host -ForeGroundColor magenta "[build] Executing requested workflow: $($Tasks -join ', ')" + Write-Host -Object "[build] Executing requested workflow: $($Tasks -join ', ')" -ForeGroundColor Magenta } finally { - Pop-Location -StackName BeforeBuild + Pop-Location -StackName 'BeforeBuild' } } Begin { - # Find build config if not specified + # Find build config if not specified. if (-not $BuildConfig) { - $config = Get-ChildItem -Path "$PSScriptRoot\*" -Include 'build.y*ml', 'build.psd1', 'build.json*' -ErrorAction:Ignore - if (-not $config -or ($config -is [array] -and $config.Length -le 0)) + $config = Get-ChildItem -Path "$PSScriptRoot\*" -Include 'build.y*ml', 'build.psd1', 'build.json*' -ErrorAction Ignore + + if (-not $config -or ($config -is [System.Array] -and $config.Length -le 0)) { - throw "No build configuration found. Specify path via -BuildConfig" + throw 'No build configuration found. Specify path via parameter BuildConfig.' } - elseif ($config -is [array]) + elseif ($config -is [System.Array]) { if ($config.Length -gt 1) { - throw "More than one build configuration found. Specify which one to use via -BuildConfig" + throw 'More than one build configuration found. Specify which path to use via parameter BuildConfig.' } + $BuildConfig = $config[0] } else @@ -242,144 +361,153 @@ Begin $BuildConfig = $config } } + # Bootstrapping the environment before using Invoke-Build as task runner - if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') + if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { - Write-Host -foregroundColor Green "[pre-build] Starting Build Init" - Push-Location $PSScriptRoot -StackName BuildModule + Write-Host -Object "[pre-build] Starting Build Init" -ForegroundColor Green + + Push-Location $PSScriptRoot -StackName 'BuildModule' } if ($RequiredModulesDirectory -in @('CurrentUser', 'AllUsers')) { - # Installing modules instead of saving them - Write-Host -foregroundColor Green "[pre-build] Required Modules will be installed for $RequiredModulesDirectory, not saved." - # Tell Resolve-Dependency to use provided scope as the -PSDependTarget if not overridden in Build.psd1 + # Installing modules instead of saving them. + Write-Host -Object "[pre-build] Required Modules will be installed to the PowerShell module path that is used for $RequiredModulesDirectory." -ForegroundColor Green + + <# + The variable $PSDependTarget will be used below when building the splatting + variable before calling Resolve-Dependency.ps1, unless overridden in the + file Resolve-Dependency.psd1. + #> $PSDependTarget = $RequiredModulesDirectory } else { - if (-Not (Split-Path -IsAbsolute -Path $OutputDirectory)) + if (-not (Split-Path -IsAbsolute -Path $OutputDirectory)) { $OutputDirectory = Join-Path -Path $PSScriptRoot -ChildPath $OutputDirectory } - # Resolving the absolute path to save the required modules to - if (-Not (Split-Path -IsAbsolute -Path $RequiredModulesDirectory)) + # Resolving the absolute path to save the required modules to. + if (-not (Split-Path -IsAbsolute -Path $RequiredModulesDirectory)) { $RequiredModulesDirectory = Join-Path -Path $PSScriptRoot -ChildPath $RequiredModulesDirectory } - # Create the output/modules folder if not exists, or resolve the Absolute path otherwise - if (Resolve-Path $RequiredModulesDirectory -ErrorAction SilentlyContinue) + # Create the output/modules folder if not exists, or resolve the Absolute path otherwise. + if (Resolve-Path -Path $RequiredModulesDirectory -ErrorAction SilentlyContinue) { - Write-Debug "[pre-build] Required Modules path already exist at $RequiredModulesDirectory" - $RequiredModulesPath = Convert-Path $RequiredModulesDirectory + Write-Debug -Message "[pre-build] Required Modules path already exist at $RequiredModulesDirectory" + + $requiredModulesPath = Convert-Path -Path $RequiredModulesDirectory } else { - Write-Host -foregroundColor Green "[pre-build] Creating required modules directory $RequiredModulesDirectory." - $RequiredModulesPath = (New-Item -ItemType Directory -Force -Path $RequiredModulesDirectory).FullName - } + Write-Host -Object "[pre-build] Creating required modules directory $RequiredModulesDirectory." -ForegroundColor Green - # Prepending $RequiredModulesPath folder to PSModulePath to resolve from this folder FIRST - if ($RequiredModulesDirectory -notIn @('CurrentUser', 'AllUsers') -and - (($Env:PSModulePath -split [io.path]::PathSeparator) -notContains $RequiredModulesDirectory)) - { - Write-Host -foregroundColor Green "[pre-build] Prepending '$RequiredModulesDirectory' folder to PSModulePath" - $Env:PSModulePath = $RequiredModulesDirectory + [io.path]::PathSeparator + $Env:PSModulePath + $requiredModulesPath = (New-Item -ItemType Directory -Force -Path $RequiredModulesDirectory).FullName } - # Checking if the user should -ResolveDependency - if ((!(Get-Module -ListAvailable powershell-yaml) -or !(Get-Module -ListAvailable InvokeBuild) -or !(Get-Module -ListAvailable PSDepend)) -and !$ResolveDependency) + $powerShellModulePaths = $env:PSModulePath -split [System.IO.Path]::PathSeparator + + # Pre-pending $requiredModulesPath folder to PSModulePath to resolve from this folder FIRST. + if ($RequiredModulesDirectory -notin @('CurrentUser', 'AllUsers') -and + ($powerShellModulePaths -notcontains $RequiredModulesDirectory)) { - if ($AutoRestore -or !$PSBoundParameters.ContainsKey('Tasks') -or $Tasks -contains 'build') - { - Write-Host -ForegroundColor Yellow "[pre-build] Dependency missing, running './build.ps1 -ResolveDependency -Tasks noop' for you `r`n" - $ResolveDependency = $true - } - else - { - Write-Warning "Some required Modules are missing, make sure you first run with the '-ResolveDependency' parameter." - Write-Warning "Running 'build.ps1 -ResolveDependency -Tasks noop' will pull required modules without running the build task." - } + Write-Host -Object "[pre-build] Pre-pending '$RequiredModulesDirectory' folder to PSModulePath" -ForegroundColor Green + + $env:PSModulePath = $RequiredModulesDirectory + [System.IO.Path]::PathSeparator + $env:PSModulePath } - if ($BuiltModuleSubdirectory) + $powerShellYamlModule = Get-Module -Name 'powershell-yaml' -ListAvailable + $invokeBuildModule = Get-Module -Name 'InvokeBuild' -ListAvailable + $psDependModule = Get-Module -Name 'PSDepend' -ListAvailable + + # Checking if the user should -ResolveDependency. + if (-not ($powerShellYamlModule -and $invokeBuildModule -and $psDependModule) -and -not $ResolveDependency) { - if (-Not (Split-Path -IsAbsolute $BuiltModuleSubdirectory)) + if ($AutoRestore -or -not $PSBoundParameters.ContainsKey('Tasks') -or $Tasks -contains 'build') { - $BuildModuleOutput = Join-Path $OutputDirectory $BuiltModuleSubdirectory + Write-Host -Object "[pre-build] Dependency missing, running './build.ps1 -ResolveDependency -Tasks noop' for you `r`n" -ForegroundColor Yellow + + $ResolveDependency = $true } else { - $BuildModuleOutput = $BuiltModuleSubdirectory + Write-Warning -Message "Some required Modules are missing, make sure you first run with the '-ResolveDependency' parameter. Running 'build.ps1 -ResolveDependency -Tasks noop' will pull required modules without running the build task." } } - else - { - $BuildModuleOutput = $OutputDirectory - } - - # Prepending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder - if (($Env:PSModulePath -split [io.path]::PathSeparator) -notContains $BuildModuleOutput) - { - Write-Host -foregroundColor Green "[pre-build] Prepending '$BuildModuleOutput' folder to PSModulePath" - $Env:PSModulePath = $BuildModuleOutput + [io.path]::PathSeparator + $Env:PSModulePath - } - # Tell Resolve-Dependency to use $RequiredModulesPath as -PSDependTarget if not overridden in Build.psd1 - $PSDependTarget = $RequiredModulesPath + <# + The variable $PSDependTarget will be used below when building the splatting + variable before calling Resolve-Dependency.ps1, unless overridden in the + file Resolve-Dependency.psd1. + #> + $PSDependTarget = $requiredModulesPath } if ($ResolveDependency) { - Write-Host -Object "[pre-build] Resolving dependencies." -foregroundColor Green - $ResolveDependencyParams = @{ } + Write-Host -Object "[pre-build] Resolving dependencies." -ForegroundColor Green + $resolveDependencyParams = @{ } - # If BuildConfig is a Yaml file, bootstrap powershell-yaml via ResolveDependency + # If BuildConfig is a Yaml file, bootstrap powershell-yaml via ResolveDependency. if ($BuildConfig -match '\.[yaml|yml]$') { - $ResolveDependencyParams.add('WithYaml', $True) + $resolveDependencyParams.Add('WithYaml', $true) } - $ResolveDependencyAvailableParams = (Get-Command -Name '.\Resolve-Dependency.ps1').parameters.keys - foreach ($CmdParameter in $ResolveDependencyAvailableParams) - { + $resolveDependencyAvailableParams = (Get-Command -Name '.\Resolve-Dependency.ps1').Parameters.Keys + foreach ($cmdParameter in $resolveDependencyAvailableParams) + { # The parameter has been explicitly used for calling the .build.ps1 - if ($MyInvocation.BoundParameters.ContainsKey($CmdParameter)) + if ($MyInvocation.BoundParameters.ContainsKey($cmdParameter)) { - $ParamValue = $MyInvocation.BoundParameters.ContainsKey($CmdParameter) - Write-Debug " adding $CmdParameter :: $ParamValue [from user-provided parameters to Build.ps1]" - $ResolveDependencyParams.Add($CmdParameter, $ParamValue) + $paramValue = $MyInvocation.BoundParameters.Item($cmdParameter) + + Write-Debug " adding $cmdParameter :: $paramValue [from user-provided parameters to Build.ps1]" + + $resolveDependencyParams.Add($cmdParameter, $paramValue) } # Use defaults parameter value from Build.ps1, if any else { - if ($ParamValue = Get-Variable -Name $CmdParameter -ValueOnly -ErrorAction Ignore) + $paramValue = Get-Variable -Name $cmdParameter -ValueOnly -ErrorAction Ignore + + if ($paramValue) { - Write-Debug " adding $CmdParameter :: $ParamValue [from default Build.ps1 variable]" - $ResolveDependencyParams.add($CmdParameter, $ParamValue) + Write-Debug " adding $cmdParameter :: $paramValue [from default Build.ps1 variable]" + + $resolveDependencyParams.Add($cmdParameter, $paramValue) } } } - Write-Host -foregroundColor Green "[pre-build] Starting bootstrap process." - .\Resolve-Dependency.ps1 @ResolveDependencyParams + Write-Host -Object "[pre-build] Starting bootstrap process." -ForegroundColor Green + + .\Resolve-Dependency.ps1 @resolveDependencyParams } - if ($MyInvocation.ScriptName -notLike '*Invoke-Build.ps1') + if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { - Write-Verbose "Bootstrap completed. Handing back to InvokeBuild." + Write-Verbose -Message "Bootstrap completed. Handing back to InvokeBuild." + if ($PSBoundParameters.ContainsKey('ResolveDependency')) { - Write-Verbose "Dependency already resolved. Removing task" + Write-Verbose -Message "Dependency already resolved. Removing task." + $null = $PSBoundParameters.Remove('ResolveDependency') } - Write-Host -foregroundColor Green "[build] Starting build with InvokeBuild." + + Write-Host -Object "[build] Starting build with InvokeBuild." -ForegroundColor Green + Invoke-Build @PSBoundParameters -Task $Tasks -File $MyInvocation.MyCommand.Path - Pop-Location -StackName BuildModule + + Pop-Location -StackName 'BuildModule' + return } } diff --git a/build.yaml b/build.yaml index a7b5ad8..536e242 100644 --- a/build.yaml +++ b/build.yaml @@ -2,7 +2,8 @@ #################################################### # ModuleBuilder Configuration # #################################################### -CopyDirectories: + +CopyPaths: - en-US - DSCResources - Modules @@ -10,15 +11,15 @@ Encoding: UTF8 VersionedOutputDirectory: true #################################################### -# ModuleBuilder Dependent Modules Configuration # +# ModuleBuilder Submodules Configuration # #################################################### NestedModule: - DscResource.Common: - CopyOnly: true - Path: ./output/RequiredModules/DscResource.Common - AddToManifest: false - Exclude: PSGetModuleInfo.xml + DscResource.Common: + CopyOnly: true + Path: ./output/RequiredModules/DscResource.Common + AddToManifest: false + Exclude: PSGetModuleInfo.xml #################################################### # Sampler Pipeline Configuration # @@ -34,6 +35,7 @@ BuildWorkflow: - Build_NestedModules_ModuleBuilder - Create_changelog_release_output - Generate_Conceptual_Help + - Generate_Wiki_Content pack: - build @@ -47,9 +49,9 @@ BuildWorkflow: - Pester_if_Code_Coverage_Under_Threshold publish: - - Publish_release_to_GitHub - publish_module_to_gallery - + - Publish_Release_To_GitHub + - Publish_GitHub_Wiki_Content #################################################### # PESTER Configuration # @@ -61,7 +63,6 @@ Pester: - Modules/DscResource.Common Script: - tests/Unit - ExcludeTag: Tag: CodeCoverageThreshold: 83 CodeCoverageOutputFile: JaCoCo_coverage.xml @@ -76,14 +77,11 @@ DscTest: ExcludeModuleFile: - Modules/DscResource.Common -Resolve-Dependency: - Gallery: '' - AllowPrerelease: false - Verbose: false - ModuleBuildTasks: Sampler: - '*.build.Sampler.ib.tasks' + Sampler.GitHubTasks: + - '*.ib.tasks' DscResource.DocGenerator: - 'Task.*' @@ -104,3 +102,16 @@ GitHubConfig: GitHubConfigUserName: dscbot GitHubConfigUserEmail: dsccommunity@outlook.com UpdateChangelogOnPrerelease: false + +#################################################### +# DscResource.DocGenerator Configuration # +#################################################### +DscResource.DocGenerator: + Generate_Conceptual_Help: + MarkdownCodeRegularExpression: + - '\`(.+?)\`' # Match inline code-block + - '\\(\\)' # Match escaped backslash + - '\[[^\[]+\]\((.+?)\)' # Match markdown URL + - '_(.+?)_' # Match Italic (underscore) + - '\*\*(.+?)\*\*' # Match bold + - '\*(.+?)\*' # Match Italic (asterisk) diff --git a/codecov.yml b/codecov.yml index 9ac402c..9d8b22a 100644 --- a/codecov.yml +++ b/codecov.yml @@ -4,7 +4,7 @@ codecov: branch: master comment: - layout: 'reach, diff' + layout: "reach, diff, flags, files" behavior: default coverage: @@ -25,4 +25,4 @@ coverage: threshold: 5 fixes: - - '\d+\.\d+\.\d+\/::source/' # move path "X.Y.Z/" => "source/" + - '^\d+\.\d+\.\d+::source' # move path "X.Y.Z" => "source" diff --git a/source/DSCResources/MSFT_xVHD/README.md b/source/DSCResources/MSFT_xVHD/README.md new file mode 100644 index 0000000..b0f90d1 --- /dev/null +++ b/source/DSCResources/MSFT_xVHD/README.md @@ -0,0 +1,8 @@ +# Description + +Manages VHDs in a Hyper-V host. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMDvdDrive/README.md b/source/DSCResources/MSFT_xVMDvdDrive/README.md new file mode 100644 index 0000000..8eded35 --- /dev/null +++ b/source/DSCResources/MSFT_xVMDvdDrive/README.md @@ -0,0 +1,8 @@ +# Description + +Manages DVD drives attached to a Hyper-V virtual machine. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMHardDiskDrive/README.md b/source/DSCResources/MSFT_xVMHardDiskDrive/README.md new file mode 100644 index 0000000..9ca45a7 --- /dev/null +++ b/source/DSCResources/MSFT_xVMHardDiskDrive/README.md @@ -0,0 +1,11 @@ +# Description + +Manages VHD(X)s attached to a Hyper-V virtual machine. + +When ControllerNumber or ControllerLocation is not provided, the same logic +as Set-VMHardDiskDrive cmdlet is used. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMHost/README.md b/source/DSCResources/MSFT_xVMHost/README.md new file mode 100644 index 0000000..56ab581 --- /dev/null +++ b/source/DSCResources/MSFT_xVMHost/README.md @@ -0,0 +1,8 @@ +# Description + +Manages Hyper-V host settings. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMHyperV/README.md b/source/DSCResources/MSFT_xVMHyperV/README.md new file mode 100644 index 0000000..5f10c9b --- /dev/null +++ b/source/DSCResources/MSFT_xVMHyperV/README.md @@ -0,0 +1,14 @@ +# Description + +Manages VMs in a Hyper-V host. + +The following properties **cannot** be changed after VM creation: + +* VhdPath +* Path +* Generation + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMNetworkAdapter/README.md b/source/DSCResources/MSFT_xVMNetworkAdapter/README.md new file mode 100644 index 0000000..d741285 --- /dev/null +++ b/source/DSCResources/MSFT_xVMNetworkAdapter/README.md @@ -0,0 +1,9 @@ +# Description + +Manages VM net adapters attached to a Hyper-V virtual machine or the +management OS. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMProcessor/README.md b/source/DSCResources/MSFT_xVMProcessor/README.md new file mode 100644 index 0000000..9297c92 --- /dev/null +++ b/source/DSCResources/MSFT_xVMProcessor/README.md @@ -0,0 +1,8 @@ +# Description + +Manages Hyper-V virtual machine processor options. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMScsiController/README.md b/source/DSCResources/MSFT_xVMScsiController/README.md new file mode 100644 index 0000000..859f31e --- /dev/null +++ b/source/DSCResources/MSFT_xVMScsiController/README.md @@ -0,0 +1,11 @@ +# Description + +Manages the SCSI controllers attached to a Hyper-V virtual machine. + +When removing a controller, all the disks still connected to the controller +will be detached. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVMSwitch/README.md b/source/DSCResources/MSFT_xVMSwitch/README.md new file mode 100644 index 0000000..45a7517 --- /dev/null +++ b/source/DSCResources/MSFT_xVMSwitch/README.md @@ -0,0 +1,8 @@ +# Description + +Manages virtual switches in a Hyper-V host. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/MSFT_xVhdFileDirectory/README.md b/source/DSCResources/MSFT_xVhdFileDirectory/README.md new file mode 100644 index 0000000..205db6b --- /dev/null +++ b/source/DSCResources/MSFT_xVhdFileDirectory/README.md @@ -0,0 +1,13 @@ +# Description + +Manages files or directories in a VHD. + +You can use it to copy files/folders to the VHD, remove files/folders +from a VHD, and change attributes of a file in a VHD (e.g. change a +file attribute to 'ReadOnly' or 'Hidden'). This resource is particularly +useful when bootstrapping DSC Configurations into a VM. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/WikiSource/Home.md b/source/WikiSource/Home.md new file mode 100644 index 0000000..fad727f --- /dev/null +++ b/source/WikiSource/Home.md @@ -0,0 +1,55 @@ +# Welcome to the xHyper-V wiki + +*xHyper-V v#.#.#* + +Here you will find all the information you need to make use of the xHyper-V +DSC resources in the latest release. This includes details of the resources +that are available, current capabilities and known issues, and information +to help plan a DSC based implementation of xHyper-V. + +Please leave comments, feature requests, and bug reports for this module in +the [issues section](https://github.com/dsccommunity/xHyper-V/issues) +for this repository. + +## Deprecated resources + +The documentation, examples, unit test, and integration tests have been removed +for these deprecated resources. These resources will be removed +in a future release. + +*No deprecated resources*. + +## Getting started + +To get started either: + +- Install from the PowerShell Gallery using PowerShellGet by running the + following command: + +```powershell +Install-Module -Name xHyper-V -Repository PSGallery +``` + +- Download xHyper-V from the [PowerShell Gallery](http://www.powershellgallery.com/packages/xHyper-V/) + and then unzip it to one of your PowerShell modules folders (such as + `$env:ProgramFiles\WindowsPowerShell\Modules`). + +To confirm installation, run the below command and ensure you see the xHyper-V +DSC resources available: + +```powershell +Get-DscResource -Module xHyper-V +``` + +## Prerequisites + +### Powershell + +The minimum Windows Management Framework (PowerShell) version required is 5.0 +or higher, which ships with Windows 10 or Windows Server 2016, +but can also be installed on Windows 7 SP1, Windows 8.1, Windows Server 2012, +and Windows Server 2012 R2. + +## Change log + +A full list of changes in each version can be found in the [change log](https://github.com/dsccommunity/xHyper-V/blob/main/CHANGELOG.md). diff --git a/source/build.psd1 b/source/build.psd1 deleted file mode 100644 index cc73d6e..0000000 --- a/source/build.psd1 +++ /dev/null @@ -1,6 +0,0 @@ -@{ - Path = 'xHyper-V.psd1' #or build breaks on Linux -} -# Waiting for ModuleBuilder to do away with this file -# when all parameters are provided to the function - diff --git a/source/xHyper-V.psd1 b/source/xHyper-V.psd1 index aa42cc1..eb40abe 100644 --- a/source/xHyper-V.psd1 +++ b/source/xHyper-V.psd1 @@ -35,18 +35,7 @@ # Aliases to export from this module AliasesToExport = @() - DscResourcesToExport = @( - 'xVHD' - 'xVhdFile' - 'xVMDvdDrive' - 'xVMHardDiskDrive' - 'xVMHost' - 'xVMHyperV' - 'xVMNetworkAdapter' - 'xVMProcessor' - 'xVMScsiController' - 'xVMSwitch' - ) + DscResourcesToExport = @() # 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 = @{ @@ -71,19 +60,3 @@ } # End of PSData hashtable } # End of PrivateData hashtable } - - - - - - - - - - - - - - - - diff --git a/source/xHyper-V.psm1 b/source/xHyper-V.psm1 new file mode 100644 index 0000000..81d556e --- /dev/null +++ b/source/xHyper-V.psm1 @@ -0,0 +1,4 @@ +<# + This file is intentionally left empty. It is must be left here for the module + manifest to refer to. It is recreated during the build process. +#>