├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .vscode ├── settings.json └── tasks.json ├── CHANGELOG.md ├── LICENSE.md ├── MODULE_README.md ├── PlasterManifest.xml ├── README.md ├── code-of-conduct.md ├── contributing.md ├── module.psm1 └── tests ├── Feature.Tests.ps1 ├── Help.Exceptions.txt ├── Help.Tests.ps1 ├── Project.Exceptions.txt ├── Project.Tests.ps1 ├── README_TESTS.md └── Unit.Tests.ps1 /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Prerequisites** 8 | 9 | Put an X between the brackets on each line to confirm you have completed them: 10 | 11 | - [ ] The issue is still present in the latest version of the module. 12 | - [ ] The issue has not been previously reported. 13 | 14 | **Describe the bug** 15 | A clear and concise description of what the bug is. 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Screenshots or Transcripts** 28 | If applicable, add screenshots or PowerShell transcripts to help explain your problem. You can use ```Start-Transcript``` and ```Stop-Transcript``` to record the steps you have performed. 29 | 30 | **System Details** 31 | 32 | - Operating System: [Windows | Linux | MacOS] 33 | - Operating System Version (Version and Build, eg Windows 10 Build 1709): 34 | - PowerShell Version: [Use ```Get-Host```] 35 | - Architecture for PowerShell Session: [64bit | 32bit] 36 | - Is this system an Azure Automation Worker?: [No, Hybrid Worker, Azure Worker] 37 | - Other loaded modules: [Include the output of ```Get-Module```] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. Is there any other information like system configuration or data that might help us understand the problem. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Examples of how the solution would work** 14 | Some simple PowerShell examples of how the solution would work. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Requirements 2 | 3 | * This template is required. Any request that does not include enough information may be closed at the maintainers' discretion. 4 | * Have you (put an X between the brackets on each line to confirm): 5 | * [ ] Written new test cases to ensure no regression bugs occur? 6 | * [ ] Ensured all test cases are now passing? 7 | * [ ] Ensured that PowerShell Script Analyser issues and warnings are completely resolved? 8 | * [ ] Updated any help or documentation that may be impacted by your changes? 9 | 10 | ### Description of the Change 11 | 12 | [ We must be able to understand the design of your change from this description. If we cannot get a good idea of what the code will be doing from the description here, the pull request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code here recently, so please walk us through the concepts. ] 13 | 14 | ### Testing 15 | 16 | [ Please describe the testing you have performed ] 17 | 18 | ### Associated/Resolved Issues 19 | 20 | [ Enter any applicable issues here ] 21 | 22 | > Note: By creating a pull request, you are expected to comply with this project's Code of Conduct. 23 | 24 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // 3 | // Custom Settings for Project 4 | // 5 | // These are here so that anyone potentially modifying the code base has the same editor experience, this ensures that the code will follow the same structure. 6 | 7 | // Controls how the editor should render whitespace characters, possibilities are 'none', 'boundary', and 'all'. The 'boundary' option does not render single spaces between words. 8 | "editor.renderWhitespace": "all", // Default: none 9 | 10 | // Controls whether the editor should render control characters 11 | "editor.renderControlCharacters": true, // Default: false 12 | 13 | // Number of spaces for tabs 14 | "editor.tabSize": 4, // Default: 4 15 | 16 | // Use spaces not tabs 17 | "editor.insertSpaces": true, // Default: true 18 | 19 | // When enabled, will trim trailing whitespace when you save a file. 20 | "files.trimTrailingWhitespace": true, // Default: false 21 | 22 | // Does not reformat one-line code blocks, such as "if (...) {...} else {...}". 23 | "powershell.codeFormatting.ignoreOneLineBlock": false, // Default: True 24 | 25 | // Adds a newline (line break) after a closing brace. 26 | "powershell.codeFormatting.newLineAfterCloseBrace": true, // Default: True 27 | 28 | // Adds a newline (line break) after an open brace. 29 | "powershell.codeFormatting.newLineAfterOpenBrace": true, // Default: True 30 | 31 | // Places open brace on the same line as its associated statement. 32 | "powershell.codeFormatting.openBraceOnSameLine": true, // Default: True 33 | 34 | // Adds a space after a separator (',' and ';'). 35 | "powershell.codeFormatting.whitespaceAfterSeparator": true, // Default: True 36 | 37 | // Adds spaces before and after an operator ('=', '+', '-', etc.). 38 | "powershell.codeFormatting.whitespaceAroundOperator": true, // Default: True 39 | 40 | // Adds a space between a keyword and its associated scriptblock expression. 41 | "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, // Default: True 42 | 43 | // Adds a space between a keyword (if, elseif, while, switch, etc) and its associated conditional expression. 44 | "powershell.codeFormatting.whitespaceBeforeOpenParen": true, // Default: True 45 | 46 | // Align assignment statements in a hashtable or a DSC Configuration. 47 | "powershell.codeFormatting.alignPropertyValuePairs": true // Default: True 48 | } 49 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${relativeFile}: the current opened file relative to workspaceRoot 5 | // ${fileBasename}: the current opened file's basename 6 | // ${fileDirname}: the current opened file's dirname 7 | // ${fileExtname}: the current opened file's extension 8 | // ${cwd}: the current working directory of the spawned process 9 | { 10 | // See https://go.microsoft.com/fwlink/?LinkId=733558 11 | // for the documentation about the tasks.json format 12 | "version": "0.1.0", 13 | 14 | // Start PowerShell 15 | "windows": { 16 | "command": "${env:windir}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe", 17 | "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass" ] 18 | }, 19 | "linux": { 20 | "command": "/usr/bin/powershell", 21 | "args": [ "-NoProfile" ] 22 | }, 23 | "osx": { 24 | "command": "/usr/local/bin/powershell", 25 | "args": [ "-NoProfile" ] 26 | }, 27 | 28 | // The command is a shell script 29 | "isShellCommand": true, 30 | 31 | // Show the output window always 32 | "showOutput": "always", 33 | 34 | // Associate with test task runner 35 | "tasks": [ 36 | { 37 | "taskName": "Test", 38 | "suppressTaskName": true, 39 | "isTestCommand": true, 40 | "showOutput": "always", 41 | "args": [ 42 | "Write-Host 'Invoking Pester'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};", 43 | "Invoke-Command { Write-Host 'Completed Test task in task runner.' }" 44 | ], 45 | "problemMatcher": [ 46 | { 47 | "owner": "powershell", 48 | "fileLocation": ["absolute"], 49 | "severity": "error", 50 | "pattern": [ 51 | { 52 | "regexp": "^\\s*(\\[-\\]\\s*.*?)(\\d+)ms\\s*$", 53 | "message": 1 54 | }, 55 | { 56 | "regexp": "^\\s+at\\s+[^,]+,\\s*(.*?):\\s+line\\s+(\\d+)$", 57 | "file": 1, 58 | "line": 2 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | ] 65 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # <%= $PLASTER_PARAM_ModuleName %> Release History 2 | 3 | ## Version Number - Release Date 4 | 5 | ### Fixed 6 | 7 | * First item fixed 8 | * Second item fixed 9 | 10 | ### Added 11 | 12 | * New item added 13 | * Another new item added 14 | 15 | ### Changed 16 | 17 | * Feature changed 18 | * Tests added 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) <%= $PLASTER_PARAM_AuthorName %> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /MODULE_README.md: -------------------------------------------------------------------------------- 1 | # <%= $PLASTER_PARAM_ModuleName %> 2 | 3 | ![Build Status](https://build.status.url.here) 4 | 5 | ## Description 6 | 7 | <%= $PLASTER_PARAM_ModuleDescription %> 8 | 9 | Authored by <%= $PLASTER_PARAM_AuthorName %> 10 | 11 | ## Installing 12 | 13 | The easiest way to get <%= $PLASTER_PARAM_ModuleName %> is using the [PowerShell Gallery](https://powershellgallery.com/packages/<%= $PLASTER_PARAM_ModuleName %>/)! 14 | 15 | ### Inspecting the module 16 | 17 | Best practice is that you inspect modules prior to installing them. You can do this by saving the module to a local path: 18 | 19 | ``` PowerShell 20 | PS> Save-Module -Name <%= $PLASTER_PARAM_ModuleName %> -Path 21 | ``` 22 | 23 | ### Installing the module 24 | 25 | Once you trust a module, you can install it using: 26 | 27 | ``` PowerShell 28 | PS> Install-Module -Name <%= $PLASTER_PARAM_ModuleName %> 29 | ``` 30 | 31 | ### Updating <%= $PLASTER_PARAM_ModuleName %> 32 | 33 | Once installed from the PowerShell Gallery, you can update it using: 34 | 35 | ``` PowerShell 36 | PS> Update-Module -Name <%= $PLASTER_PARAM_ModuleName %> 37 | ``` 38 | 39 | ### Uninstalling <%= $PLASTER_PARAM_ModuleName %> 40 | 41 | To uninstall <%= $PLASTER_PARAM_ModuleName %>: 42 | 43 | ``` PowerShell 44 | PS> Uninstall-Module -Name <%= $PLASTER_PARAM_ModuleName %> 45 | ``` 46 | 47 | ## Contributing to <%= $PLASTER_PARAM_ModuleName %> 48 | 49 | Interested in contributing? Read how you can [Contribute](contributing.md) to <%= $PLASTER_PARAM_ModuleName %> 50 | 51 | This project maintains a [Code of Conduct](code-of-conduct.md) that establishes how the project is governed and how everyone involved is expected to behave. You can report unacceptable behavior to [<%= $PLASTER_PARAM_AuthorEmail %>](mailto:<%= $PLASTER_PARAM_AuthorEmail %>). 52 | 53 | ## Release History 54 | 55 | A detailed release history is contained in the [Change Log](CHANGELOG.md). 56 | 57 | ## License 58 | 59 | <%= $PLASTER_PARAM_ModuleName %> is provided under the [MIT license](LICENSE.md). -------------------------------------------------------------------------------- /PlasterManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | StandardModuleTemplate 5 | a9c355a8-0228-4f58-8df9-3291dd997c1e 6 | 1.0.0 7 | Standard Module Template 8 | 9 | Kieran Jacobsen 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Creating test folder and files 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Creating VSCode folder and files 44 | 45 | 46 | 47 | Creating code folders 48 | 49 | 50 | 51 | 52 | Creating GitHub folder and files 53 | 54 | 55 | 56 | 57 | 58 | 59 | Creating license file 60 | 61 | Deploying root directory files 62 | 63 | 64 | 65 | Creating module manifest 66 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Using this Plaster Template 2 | 3 | The contents of this GitHub repostiory form a PowerShell [Plaster](https://github.com/PowerShell/Plaster/) template. 4 | 5 | This template was created by [Kieran Jacobsen](https://github.com/poshsecurity), based upon the work of [Rob Sewell](https://github.com/sqldbawithabeard). 6 | 7 | The goal of this template is to provide a strong structure for PowerShell module development and to encourage community participation via GitHub. 8 | 9 | ## Installing Plaster 10 | 11 | You can install Plaster from the [PowerShell Gallery](https://powershellgallery.com/packages/Plaster/) 12 | 13 | ``` PowerShell 14 | PS> Install-Module -Name Plaster 15 | ``` 16 | 17 | ## Clone the template 18 | 19 | Using Git you can clone the template locally. 20 | 21 | ``` PowerShell 22 | PS> git clone https://github.com/poshsecurity/PlasterTemplate 23 | ``` 24 | 25 | ## Creating a new module 26 | 27 | Now that you have template locally, you can run ```Invoke-Plaster``` to create a new module based upon the template. 28 | 29 | I typically follow this workflow: 30 | 31 | 1. Create a public (or private) on GitHub 32 | 2. Clone the repository locally 33 | ``` PowerShell 34 | PS> git clone 35 | ``` 36 | 3. Create a hash table containing the required parameters, and then call ```Invoke-Plaster``` 37 | ``` PowerShell 38 | PS> $PlasterParameters = @{ 39 | TemplatePath = "" 40 | DestinationPath = "" 41 | AuthorName = "Cool PowerShell Developer" 42 | AuthorEmail = "Developer@PowerShellis.Cool" 43 | ModuleName = "MyNewModule" 44 | ModuleDescription = "This is my awesome PowerShell Module!" 45 | ModuleVersion = "0.1" 46 | ModuleFolders = @("functions", "internal") 47 | GitHub = "Yes" 48 | License = "Yes" 49 | } 50 | 51 | PS> Invoke-Plaster @PlasterParameters 52 | ``` 53 | 4. Plaster should then execute, creating the required files and folders. 54 | 5. When you are ready you can push everything up to GitHub. 55 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at <%= $PLASTER_PARAM_AuthorEmail %>. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 44 | 45 | [homepage]: https://www.contributor-covenant.org 46 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | See an issue that you can help with? Have an idea for the next great feature? Thanks for taking the time to contribute!!! 4 | 5 | Here are some guidelines for contributing to this project. They are not hard rules, just guidelines. 6 | 7 | ## Code of Conduct 8 | 9 | This project maintains a [code of conduct](code-of-conduct.md) that establishes how the project is governed and how everyone involved is expected to behave. 10 | 11 | You can report unacceptable behavior to [<%= $PLASTER_PARAM_AuthorEmail %>](mailto:<%= $PLASTER_PARAM_AuthorEmail %>). 12 | 13 | ## TL;DR 14 | 15 | * Check if any bugs/issues/features have been previously reported/requested before creating a new issue. 16 | * Ensure you are using the LATEST version before raising a new issue. 17 | * Ensure you complete the Pull Request template when raising a new PR. 18 | 19 | ## Reporting Bugs/Issues 20 | 21 | The reality is that code will contain bugs, even with thorough testing, issues can get through. Following these guidelines will help the maintainers to understand the issue you have encountered, reproduce the problem and fix it! You might even find that you don't need to create one. 22 | 23 | > **Note:** If you find an issue that is Closed that seems like what you are experiencing, please open a **new** issue and include a link to the previous issue in your description. 24 | 25 | ### Before you file a bug report 26 | 27 | * **Ensure you are running the latest version of the module.** If you are running an older version of the module, try updating the module and testing if the issue remains. If you installed the module from the [PowerShell Gallery](https://powershellgallery.com), use this command to update the module: ``` PS> Update-Module -Name <%= $PLASTER_PARAM_ModuleName %> ```. 28 | * **Ensure that you are using the CMDLet correctly.** Have you checked the help? Sometimes we assume we know how a specific function or CMDLet works, and it turns out we are wrong. The command ```Get-Help``` is your friend! 29 | * **Has the issue been reported before?** You might not be the only person who has reported the issue. Check out the [Issues][Issues] and look through any current Issues that may match the issue you are experiencing. 30 | 31 | ### Submitting a (good) bug report 32 | 33 | Bugs and problems are tracked using [GitHub issues](https://guides.github.com/features/issues/). To submit a bug, create an issue and provide the information requested in [the template](ISSUE_TEMPLATE.md). The template will help the maintainers to resolve issues faster. 34 | 35 | Here are some tips on ensuring you create an excellent bug report: 36 | 37 | * **Bugs should be actionable**, that is, something that can be fixed as part of this project. Issues with Windows, .Net or PowerShell might not be solvable within this project. 38 | * **Use a clear descriptive title** for the issue that describes the issue. 39 | * **Describe the exact steps to reproduce the issue** and include as many details as possible. People often leave things out as they think they might not be important, but every little detail counts! When listing what steps or commands you executed, **don't just say what you did, try to explain how you did it**. Be as detailed as possible, it is safe to say that more is usually better. 40 | * **Provide specific examples**, include specific steps you have taken, link to files or other copy/pastable snippets. If you are providing snippets of code, ensure you use Markdown Code Blocks. <>TODO: link<> If you can, provide the exact steps/code you were executing when the issue happened. 41 | * **PowerShell Transcripts can be extremely useful** so please include those where possible. You can start a transcript with ```Start-Transcript``` and end it with ```Stop-Transcript```. 42 | * **Screenshots and Gifs** can also be extemely useful, however transcripts are preferred. 43 | * **If there is private/confidential information**, feel free to remove that from any logs/transcripts/images, but remember to highlight where you have done so. 44 | * **Describe the behavior you observed after following the steps you described** and then clearly state what the problem is with this behavior. Sometimes it isn't clear why something is an issue. 45 | * **Describe what behaviour you would expect** others might be expecting different behaviors. 46 | * **Include stack traces where possible**. If you have access to the Exception, the ```ScriptStackTrace``` and other properties may point to where the problem is. 47 | * **Include details about your environment** including Windows/Linux/Mac OSX version, PowerShell versions and 64/32 bit environments. If you are using Azure Automation, please ensure you mention if this is the Azure Worker or a Hybrid Worker. It can also help to include any other modules you might be using. 48 | * **Subscribe to notifications** so you can answer any follow-up questions, and assist in testing the final fixes for the issue. 49 | * **Just because you think the issue might be easy, doesn't mean it is so**. Issues can be quite complex when you actually look into them, resolution may take time so be patient. 50 | 51 | ## Suggesting New Features and Enhancements 52 | 53 | Got a killer idea for a new feature? Maybe you want to suggest a minor improvement or some totally new features? These guidelines will help maintainers understand your suggestion! 54 | 55 | ### Before you submit an enhancement suggestion 56 | 57 | * **Ensure you are running the latest version of the module.** The feature you require might be included in a new version of the module. If you installed the module from the Gallery, use this command to update the module: ``` PS> Update-Module -Name <%= $PLASTER_PARAM_ModuleName %> ```. 58 | * **Ensure that you are using the CMDLet correctly.** Have you checked the help? Perhaps the feature has already been implemented but you just haven't discovered it yet! The command ```Get-Help``` is your friend! 59 | * **Has the feature been requested before?** You might not be the only person who has requested this new feature. If it has, add a comment to the existing issue instead of opening a new one. Be sure to checkout closed issues as well, the feature may have been previously implemented or rejected. 60 | 61 | ### Submitting a (good) enhancement suggestion 62 | 63 | Enhancements are tracked via [GitHub issues](https://guides.github.com/features/issues/) just as bugs are. To submit a suggestion, create an issue and provide the information requested in [the template](ISSUE_TEMPLATE.md). 64 | 65 | Here are some tips on ensuring you create an excellent suggestion: 66 | 67 | * **Enhancements should be actionable**, that is, something that can/should be included in the project. Does the enhancement fall inside or outside the scope of the module? Modules should closely align to a specific set of activities, for instance a database query CMDLet probably shouldn't be included in a module relating to network connections. 68 | * **Use a clear descriptive title** for the issue that describes the suggestion. 69 | * **Describe the new functionality or enhancement**, provide a step-by-step description of how it would function. 70 | * **Describe the current behavior and expected behavior** you would like to see. 71 | * **Provide specific examples** including how the feature would work, error handling, validation, etc. 72 | * **Describe why this would be useful** to implement this suggestion. Is this something other users might want or just something you require? 73 | * **Subscribe to notifications** so you can answer any follow-up questions, and assist in testing the final fixes for the issue. 74 | * **Just because you think the feature might be easy to implement, doesn't mean it is so**. New features could be simple, or they might require significant effort to implement, please be patient. 75 | 76 | ## Code Contributions 77 | 78 | ### Your First Contribution 79 | 80 | Looking to make your first contribution? Congratulations, you are taking the first steps into an amazing journey. 81 | 82 | Don't know where to start? You can start by looking through the issues for the **Beginner** and **Help Wanted** tags: 83 | * **Beginner** are simple and should only take a few lines of code and tests to complete. 84 | * **Help Wanted** are more involved and will take more effort to complete. 85 | 86 | ### Pull Requests 87 | 88 | Pull requests are always more than welcome. When creating a pull request, ensure that you complete [the template](PULL_REQUEST_TEMPLATE.md). 89 | 90 | Here are a few guidelines that should be followed: 91 | 92 | * Each pull request should accomplish a clear goal. Ensure that you clearly state in the request what it accomplishes. 93 | * Bug fixes: What was the bug? How did you fix it? 94 | * New features: What is it? How is it used? 95 | * Provide a high level explanation of what you are changing, it makes it easier to review. 96 | * Keep requests small, as it: 97 | * Makes reviews easier. 98 | * Makes testing easier. 99 | * Helps review conflicts more easily. 100 | * Ensure that all Pester tests pass and there are no failures. 101 | * Ensure that there are no errors or warnings with PowerShell Script Analyzer 102 | * Any new code needs to have tests created: 103 | * Bug fixes: Consider test cases that would have failed before the change but pass now. 104 | * New features: Test cases need to ensure that new features function correctly and existing features still function as previously expected. 105 | * Ensure that any code you write aligns with community style guides. 106 | * Don't include issue numbers in the PR title. 107 | * Ensure that your branch is up-to-date to reduce the merge conflicts that could occur. 108 | ### Things that might get your Pull Request rejected 109 | 110 | There are often things in Pull Requests that might lead to a pull request being rejected, these include: 111 | 112 | * Malicious code. 113 | * Code that breaks previous functionality in a way that could be avoided. 114 | * Code that doesn't align with community style recommendations. 115 | * Code that fails Pester tests or PowerShell Script analyser. 116 | * Code that is obviously plagiarised. 117 | 118 | -------------------------------------------------------------------------------- /module.psm1: -------------------------------------------------------------------------------- 1 | # Taken from http://overpoweredshell.com/Working-with-Plaster/ 2 | 3 | $functionFolders = @('functions', 'internal', 'classes') 4 | ForEach ($folder in $functionFolders) 5 | { 6 | $folderPath = Join-Path -Path $PSScriptRoot -ChildPath $folder 7 | If (Test-Path -Path $folderPath) 8 | { 9 | Write-Verbose -Message "Importing from $folder" 10 | $functions = Get-ChildItem -Path $folderPath -Filter '*.ps1' 11 | ForEach ($function in $functions) 12 | { 13 | Write-Verbose -Message " Importing $($function.BaseName)" 14 | . $function.providerpath 15 | } 16 | } 17 | } 18 | $publicFunctions = (Get-ChildItem -Path "$PSScriptRoot\functions" -Filter '*.ps1').BaseName 19 | Export-ModuleMember -Function $publicFunctions 20 | -------------------------------------------------------------------------------- /tests/Feature.Tests.ps1: -------------------------------------------------------------------------------- 1 | $script:ModuleName = '<%= $PLASTER_PARAM_ModuleName %>' 2 | 3 | # Removes all versions of the module from the session before importing 4 | Get-Module $ModuleName | Remove-Module 5 | 6 | $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path 7 | 8 | # For tests in .\Tests subdirectory 9 | if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { 10 | $ModuleBase = Split-Path $ModuleBase -Parent 11 | } 12 | 13 | ## This variable is for the VSTS tasks and is to be used for referencing any mock artifacts 14 | $Env:ModuleBase = $ModuleBase 15 | 16 | Import-Module $ModuleBase\$ModuleName.psd1 -PassThru -ErrorAction Stop | Out-Null 17 | Describe "Basic function feature tests" -Tags Build { 18 | 19 | } -------------------------------------------------------------------------------- /tests/Help.Exceptions.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/Help.Tests.ps1: -------------------------------------------------------------------------------- 1 | $script:ModuleName = '<%= $PLASTER_PARAM_ModuleName %>' 2 | 3 | # Removes all versions of the module from the session before importing 4 | Get-Module $ModuleName | Remove-Module 5 | 6 | $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path 7 | 8 | # Get the list of functions we are not going to run tests against 9 | $FunctionHelpTestExceptions = Get-Content -Path "$ModuleBase\Help.Exceptions.txt" 10 | 11 | # For tests in .\Tests subdirectory 12 | if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { 13 | $ModuleBase = Split-Path $ModuleBase -Parent 14 | } 15 | 16 | $Module = Import-Module $ModuleBase\$ModuleName.psd1 -PassThru -ErrorAction Stop 17 | $commands = Get-Command -Module $module -CommandType Cmdlet, Function, Workflow # Not alias 18 | 19 | ## When testing help, remember that help is cached at the beginning of each session. 20 | ## To test, restart session. 21 | 22 | foreach ($command in $commands) { 23 | $commandName = $command.Name 24 | 25 | # Skip all functions that are on the exclusions list 26 | if ($script:FunctionHelpTestExceptions -contains $commandName) { continue } ## may not be correct check with a function that needs exceptions 27 | 28 | # The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets 29 | $Help = Get-Help $commandName -ErrorAction SilentlyContinue 30 | 31 | Describe "Test help for $commandName" -Tag Help { 32 | 33 | # If help is not found, synopsis in auto-generated help is the syntax diagram 34 | It "should not be auto-generated" { 35 | $Help.Synopsis | Should Not BeLike '*`[``]*' 36 | } 37 | 38 | # Should be a description for every function 39 | It "gets description for $commandName" { 40 | $Help.Description | Should Not BeNullOrEmpty 41 | } 42 | 43 | # Should be at least one example 44 | It "gets example code from $commandName" { 45 | ($Help.Examples.Example | Select-Object -First 1).Code | Should Not BeNullOrEmpty 46 | } 47 | 48 | # Should be at least one example description 49 | It "gets example help from $commandName" { 50 | ($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should Not BeNullOrEmpty 51 | } 52 | 53 | Context "Test parameter help for $commandName" { 54 | 55 | $Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 56 | 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable' 57 | 58 | $parameters = $command.ParameterSets.Parameters | Sort-Object -Property Name -Unique | Where-Object Name -notin $common 59 | $parameterNames = $parameters.Name 60 | $HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique 61 | 62 | foreach ($parameter in $parameters) { 63 | $parameterName = $parameter.Name 64 | $parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName 65 | 66 | # Should be a description for every parameter 67 | It "gets help for parameter: $parameterName : in $commandName" { 68 | $parameterHelp.Description.Text | Should Not BeNullOrEmpty 69 | } 70 | 71 | # Required value in Help should match IsMandatory property of parameter 72 | It "help for $parameterName parameter in $commandName has correct Mandatory value" { 73 | $codeMandatory = $parameter.IsMandatory.toString() 74 | $parameterHelp.Required | Should Be $codeMandatory 75 | } 76 | 77 | # Parameter type in Help should match code 78 | It "help for $commandName has correct parameter type for $parameterName" { 79 | $codeType = $parameter.ParameterType.Name 80 | # To avoid calling Trim method on a null object. 81 | $helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() } 82 | $helpType | Should be $codeType 83 | } 84 | } 85 | 86 | foreach ($helpParm in $HelpParameterNames) { 87 | # Shouldn't find extra parameters in help. 88 | It "finds help parameter in code: $helpParm" { 89 | $helpParm -in $parameterNames | Should Be $true 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Project.Exceptions.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poshsecurity/PlasterTemplate-PSModule/1ff0e4141ab39a18f0df3cdfb54ba1bbfe744dde/tests/Project.Exceptions.txt -------------------------------------------------------------------------------- /tests/Project.Tests.ps1: -------------------------------------------------------------------------------- 1 | if (-not(Get-Module -ListAvailable -Name "PSScriptAnalyzer")) { 2 | Write-Warning "Installing latest version of PSScriptAnalyzer" 3 | # Install PSScriptAnalyzer 4 | Install-Module PSScriptAnalyzer -Force -Scope CurrentUser 5 | } 6 | 7 | $script:ModuleName = '<%= $PLASTER_PARAM_ModuleName %>' 8 | 9 | $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path 10 | 11 | # Get the list of Pester Tests we are going to skip 12 | $PesterTestExceptions = Get-Content -Path "$ModuleBase\Project.Exceptions.txt" 13 | 14 | # For tests in .\Tests subdirectory 15 | if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { 16 | $ModuleBase = Split-Path $ModuleBase -Parent 17 | } 18 | 19 | Describe "PSScriptAnalyzer rule-sets" -Tag Build , ScriptAnalyzer { 20 | 21 | $Rules = Get-ScriptAnalyzerRule 22 | $scripts = Get-ChildItem $ModuleBase -Include *.ps1, *.psm1, *.psd1 -Recurse | Where-Object fullname -notmatch 'classes' 23 | 24 | foreach ( $Script in $scripts ) 25 | { 26 | Context "Script '$($script.FullName)'" { 27 | 28 | foreach ( $rule in $rules ) 29 | { 30 | # Skip all rules that are on the exclusions list 31 | if ($PesterTestExceptions -contains $rule.RuleName) { continue } 32 | It "Rule [$rule]" { 33 | 34 | (Invoke-ScriptAnalyzer -Path $script.FullName -IncludeRule $rule.RuleName ).Count | Should Be 0 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | 42 | Describe "General project validation: $moduleName" -Tags Build { 43 | BeforeAll { 44 | Get-Module $ModuleName | Remove-Module 45 | } 46 | It "Module '$moduleName' can import cleanly" { 47 | {Import-Module $ModuleBase\$ModuleName.psd1 -force } | Should Not Throw 48 | } 49 | } -------------------------------------------------------------------------------- /tests/README_TESTS.md: -------------------------------------------------------------------------------- 1 | # Understanding Tests 2 | 3 | This template comes with the following files: 4 | 5 | * **Feature.Tests.ps1** - Place tests of the features of the module within this file. 6 | * **Help.Exceptions.txt** - If there are functions you wish to exclude from the Comment Based Help tests, place their names in this file. 7 | * **Help.Tests.ps1** - Performs tests on the Comment Based Help for public functions within the module. You shouldn't need to edit this file. 8 | * **Project.Exceptions.txt** - If there are specific PowerShell Script Analyser tests you wish to disable, place their names in this file. I recommend however to use the exclusions listed at the top of your functions. 9 | * **Project.Tests.ps1** - Tests that your module meets all PowerShell Script Analyser tests. Also tests that the module successfully loads. 10 | * **Unit.Tests.ps1** - This provides a basic structure for your unit tests. Best practice is to copy this file for each function/CMDLet within the module. This structure allows for the execution of the tests for a specific function/CMDLet. -------------------------------------------------------------------------------- /tests/Unit.Tests.ps1: -------------------------------------------------------------------------------- 1 | $script:ModuleName = '<%= $PLASTER_PARAM_ModuleName %>' 2 | 3 | # Removes all versions of the module from the session before importing 4 | Get-Module $ModuleName | Remove-Module 5 | 6 | $ModuleBase = Split-Path -Parent $MyInvocation.MyCommand.Path 7 | 8 | # For tests in .\Tests subdirectory 9 | if ((Split-Path $ModuleBase -Leaf) -eq 'Tests') { 10 | $ModuleBase = Split-Path $ModuleBase -Parent 11 | } 12 | 13 | ## This variable is for the VSTS tasks and is to be used for referencing any mock artifacts 14 | $Env:ModuleBase = $ModuleBase 15 | 16 | Import-Module $ModuleBase\$ModuleName.psd1 -PassThru -ErrorAction Stop | Out-Null 17 | 18 | # InModuleScope runs the test in module scope. 19 | # It creates all variables and functions in module scope. 20 | # As a result, test has access to all functions, variables and aliases 21 | # in the module even if they're not exported. 22 | InModuleScope $script:ModuleName { 23 | Describe "Basic function unit tests" -Tags Build , Unit{ 24 | 25 | } 26 | 27 | } --------------------------------------------------------------------------------