diff --git a/PowerShellBestPractices.md b/PowerShellBestPractices.md deleted file mode 100644 index 717810394..000000000 --- a/PowerShellBestPractices.md +++ /dev/null @@ -1,146 +0,0 @@ -# PowerShell Best Practices - -The following guidelines come from a combined effort from both the PowerShell team and the community. We will use this guideline to define rules for `PSScriptAnalyzer`. Please feel free to propose additional guidelines and rules for `PSScriptAnalyzer`. -**Note**: The hyperlink next to each guidelines will redirect to documentation page for the rule that is already implemented. - -## Cmdlet Design Rules - -### Severity: Error - -### Severity: Warning - -- Use Only Approved Verbs [UseApprovedVerbs](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseApprovedVerbs.md) -- Cmdlets Names: Characters that cannot be Used [AvoidReservedCharInCmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedCmdletChar.md) -- Parameter Names that cannot be Used [AvoidReservedParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedParams.md) -- Support Confirmation Requests [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) and [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) -- Must call ShouldProcess when ShouldProcess attribute is present and vice versa.[UseShouldProcess](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ShouldProcess.md) -- Nouns should be singular [UseSingularNouns](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseSingularNouns.md) -- Module Manifest Fields [MissingModuleManifestField](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/MissingModuleManifestField.md) - - Version - - Author - - Description - - LicenseUri (for PowerShell Gallery) -- Switch parameters should not default to true  [AvoidDefaultValueSwitchParameter](https://github.com/PowetrShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidDefaultValueSwitchParameter.md) - -### Severity: Information - -### Severity: TBD - -- Support Force Parameter for Interactive Session -- If your cmdlet is used interactively, always provide a Force parameter to override the interactive actions, such as prompts or reading lines of input). This is important because it allows your cmdlet to be used in non-interactive scripts and hosts. The following methods can be implemented by an interactive host. -- Document Output Objects -- Module must be loadable -- No syntax errors -- Unresolved dependencies are an error -- Derive from the Cmdlet or PSCmdlet Classes -- Specify the Cmdlet Attribute -- Override an Input Processing Method -- Specify the OutputType Attribute -- Write Single Records to the Pipeline -- Make Cmdlets Case-Insensitive and Case-Preserving - -## Script Functions - -### Severity: Error - -### Severity: Warning - -- Avoid using alias [AvoidUsingCmdletAliases](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingCmdletAliases.md) -- Avoid using deprecated WMI cmdlets [AvoidUsingWMICmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWMICmdlet.md) -- Empty catch block should not be used [AvoidUsingEmptyCatchBlock](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingEmptyCatchBlock.md) -- Invoke existing cmdlet with correct parameters [UseCmdletCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseCmdletCorrectly.md) -- Cmdlets should have ShouldProcess/ShouldContinue and Force param if certain system-modding verbs are present (Update, Set, Remove, New): [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) -- Positional parameters should be avoided [AvoidUsingPositionalParameters](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPositionalParameters.md) -- Global variables should be avoided. [AvoidGlobalVars](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidGlobalVars.md) -- Declared variables must be used in more than just their assignment. [UseDeclaredVarsMoreThanAssignments](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md) -- No Invoke-Expression [AvoidUsingInvokeExpression](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingInvokeExpression.md) - -### Severity: Information - -### Severity: TBD - -- `Clear-Host` should not be used -- File paths should not be used (UNC) -- Error Handling - - Use `-ErrorAction Stop` when calling cmdlets - - Use $ErrorActionPreference = 'Stop'/' Continue' when calling non-cmdlets - - Avoid using flags to handle errors - - Avoid using `$?` - - Avoid testing for a null variable as an error condition - - Copy `$Error[0]` to your own variable -- Avoid using pipelines in scripts -- If a return type is declared, the cmdlet must return that type. If a type is returned, a return type must be declared. - -## Scripting Style - -### Severity: Error - -### Severity: Warning - -- Don't use `Write-Host` unless writing to the host is all you want to do [AvoidUsingWriteHost](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWriteHost.md) - -### Severity: Information - -- Write comment-based help [ProvideCommentHelp](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ProvideCommentHelp.md) - -### Severity: TBD - -- Provide usage Examples -- Use the Notes section for detail on how the tool work -- Should have help on every exported command (including parameter documentation -- Document the version of PowerShell that script was written for -- Indent your code -- Avoid backticks - -## Script Security - -### Severity: Error - -- Password should be secure string [AvoidUsingPlainTextForPassword](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPlainTextForPassword.md)- Should never have both -Username and -Password parameters (should take credentials): [UsePSCredentialType](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UsePSCredentialType.md) -- `-ComputerName` Parameter argument hardcoded should not be used (information disclosure): [AvoidUsingComputerNameHardcoded](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingComputerNameHardcoded.md) -- ConvertTo-SecureString with plaintext should not be used (information disclosure): [AvoidUsingConvertToSecureStringWithPlainText](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md) - -### Severity: Warning - -- Password = 'string' should not be used. (information disclosure) [AvoidUsingUsernameAndPasswordParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md) - -### Severity: Information - -### Severity: TBD - -- APIKey and Credentials variables that are initialized (information disclosure) - -## DSC Related Rules - -### Severity: Error - -- Use standard DSC methods [StandardDSCFunctionsInResource](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/StandardDSCFunctionsInResource.md) -- Use identical mandatory parameters for all DSC methods [UseIdenticalMandatoryParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md) -- Use identical parameters for Set and Test DSC methods [UseIdenticalParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalParametersForDSC.md) - -### Severity: Warning - -### Severity: Information - -- All of the following three rule are grouped by: [ReturnCorrectTypesForDSCFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReturnCorrectTypesForDSCFunctions.md) -- Avoid return any object from a `Set-TargetResource` or Set (Class Based) function -- Returning a Boolean object from a `Test-TargetResource` or Test (Class Based) function -- Returning an object from a `Get-TargetResource` or Get (Class Based) function -- DSC resources should have DSC tests [DSCTestsPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscTestsPresent.md) -- DSC resources should have DSC examples [DSCExamplesPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscExamplesPresent.md) - -### Severity: TBD - -- For PowerShell V4: Resource module contains `.psd1` file and `schema.mof` for every resource -- MOF has description for each element [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/131) -- Resource module must contain .psd1 file (always) and schema.mof (for non-class resource). [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/116) -- Use ShouldProcess for a Set DSC method -- Resource module contains DscResources folder which contains the resources [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/130) - -### Reference - -* Cmdlet Development Guidelines from MSDN site (Cmdlet Development Guidelines): https://msdn.microsoft.com/en-us/library/ms714657(v=vs.85).aspx -* The Community Book of PowerShell Practices (Compiled by Don Jones and Matt Penny and the Windows PowerShell Community): https://powershell.org/community-book-of-powershell-practices/ -* PowerShell DSC Resource Design and Testing Checklist: https://blogs.msdn.com/b/powershell/archive/2014/11/18/powershell-dsc-resource-design-and-testing-checklist.aspx -* DSC Guidelines can also be found in the DSC Resources Repository: https://github.com/PowerShell/DscResources -* The Unofficial PowerShell Best Practices and Style Guide: https://github.com/PoshCode/PowerShellPracticeAndStyle diff --git a/README.md b/README.md index 4a70ba153..1308dff86 100644 --- a/README.md +++ b/README.md @@ -12,23 +12,7 @@ - [Introduction](#introduction) - [Documentation Notice](#documentation-notice) -- [Usage](#usage) - [Installation](#installation) - - [From PowerShell Gallery](#from-powershell-gallery) - - [Supported PowerShell Versions and Platforms](#supported-powerShell-versions-and-platforms) - - [From Source](#from-source) - - [Requirements](#requirements) - - [Steps](#steps) - - [Tests](#tests) -- [Suppressing Rules](#suppressing-rules) -- [Settings Support in ScriptAnalyzer](#settings-support-in-scriptanalyzer) - - [Built-in Presets](#built-in-presets) - - [Explicit](#explicit) - - [Implicit](#implicit) -- [Custom rules](#custom-rules) - - [Using custom rules in Visual Studio Code](#using-custom-rules-in-visual-studio-code) -- [ScriptAnalyzer as a .NET library](#scriptanalyzer-as-a-net-library) -- [Violation Correction](#violation-correction) - [Contributions are welcome](#contributions-are-welcome) - [Creating a Release](#creating-a-release) - [Code of Conduct](#code-of-conduct) @@ -52,17 +36,14 @@ supported. ## DOCUMENTATION NOTICE -We are in the process of moving user documentation out of the source code repository and into the -documentation repository so that it can be published on docs.microsoft.com - -After a month, any documentation that has been copied to the docs repository will be removed from -the source code repository. +Conceptual user documentation has been moved out of the source code repository and into the +documentation repository so that it can be published on docs.microsoft.com. The goal of this migration is to have the user documentation on docs.microsoft.com. The source code repository should only contain documentation for the code base, such as how to build the code or how to contribute to the code. -Some content has already been migrated: +User documentation that has been migrated: - Most of the contents of this README can be found in the [PSScriptAnalyzer overview](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/overview) @@ -70,99 +51,33 @@ Some content has already been migrated: [PSScriptAnalyzer](https://docs.microsoft.com/powershell/module/psscriptanalyzer) - For rules, see [Rules overview](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/rules/readme) +- The `PowerShellBestPractices.md` content has been moved to + [PSScriptAnalyzer rules and recommendations](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/rules-recommendations) +- The `ScriptRuleDocumentation.md` content has been moved to + [Creating custom rules](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/create-custom-rule) There is one exception - the documentation for the rules and cmdlets will remain in the [docs](docs) folder to facilitate build testing and to be archived as part of each release. Only the documentation for the latest release is published on on docs.microsoft.com. -## Usage - -```powershell -Get-ScriptAnalyzerRule [-CustomRulePath ] [-RecurseCustomRulePath] [-Name ] [-Severity ] [] - -Invoke-ScriptAnalyzer [-Path] [-CustomRulePath ] [-RecurseCustomRulePath] - [-IncludeDefaultRules] [-ExcludeRule ] [-IncludeRule ] [-Severity ] [-Recurse] - [-SuppressedOnly] [-Fix] [-EnableExit] [-Settings ] [-SaveDscDependency] [-ReportSummary] [-WhatIf] - [-Confirm] [] - -Invoke-ScriptAnalyzer [-Path] [-CustomRulePath ] [-RecurseCustomRulePath] - [-IncludeDefaultRules] [-ExcludeRule ] [-IncludeRule ] [-Severity ] [-Recurse] - [-IncludeSuppressed] [-Fix] [-EnableExit] [-Settings ] [-SaveDscDependency] [-ReportSummary] [-WhatIf] - [-Confirm] [] - -Invoke-ScriptAnalyzer [-ScriptDefinition] [-CustomRulePath ] [-RecurseCustomRulePath] - [-IncludeDefaultRules] [-ExcludeRule ] [-IncludeRule ] [-Severity ] - [-IncludeSuppressed] [-EnableExit] [-Settings ] [-SaveDscDependency] [-ReportSummary] [-WhatIf] - [-Confirm] [] - -Invoke-ScriptAnalyzer [-ScriptDefinition] [-CustomRulePath ] [-RecurseCustomRulePath] - [-IncludeDefaultRules] [-ExcludeRule ] [-IncludeRule ] [-Severity ] - [-SuppressedOnly] [-EnableExit] [-Settings ] [-SaveDscDependency] [-ReportSummary] [-WhatIf] - [-Confirm] [] - -Invoke-Formatter [-ScriptDefinition] [[-Settings] ] [[-Range] ] [] -``` - -[Back to ToC](#table-of-contents) - ## Installation -### From PowerShell Gallery +To install **PSScriptAnalyzer** from the PowerShell Gallery, see +[Installing PSScriptAnalyzer](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/overview#installing-psscriptanalyzer). -```powershell -Install-Module -Name PSScriptAnalyzer -``` - -**Note**: For PowerShell version `5.1.14393.206` or newer, before installing PSScriptAnalyzer, -please install the latest NuGet provider by running the following in an elevated PowerShell session. - -```powershell -Install-PackageProvider NuGet -MinimumVersion 2.8.5.201 -Force -Exit -``` +To install **PSScriptAnalyzer** from source code: -#### Supported PowerShell Versions and Platforms +### Requirements -- Windows PowerShell 3.0 or greater -- PowerShell Core 7.0.3 or greater on Windows/Linux/macOS -- Docker (tested only using Docker Desktop on Windows 10 1809) - - PowerShell 6 Windows Image tags from - [mcr.microsoft.com/powershell](https://hub.docker.com/r/microsoft/powershell). Example (1 - warning gets produced by `Save-Module` but can be ignored): - - ```powershell - docker run -it mcr.microsoft.com/powershell:nanoserver pwsh -command "Save-Module -Name PSScriptAnalyzer -Path .; Import-Module .\PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'" - ``` - - - PowerShell 5.1 (Windows): Only the - [mcr.microsoft.com/windowsservercore](https://hub.docker.com/r/microsoft/windowsservercore/) - images work but not the - [microsoft/nanoserver](https://hub.docker.com/r/microsoft/windowsservercore/) images because - they contain a Core version of it. Example: - - ```powershell - docker run -it mcr.microsoft.com/windowsservercore powershell -command "Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force; Install-Module PSScriptAnalyzer -Force; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'" - ``` - - - Linux tags from [mcr.microsoft.com/powershell](https://hub.docker.com/r/microsoft/powershell/). - - ```powershell - docker run -it mcr.microsoft.com/powershell pwsh -c "Install-Module PSScriptAnalyzer -Force; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'" - ``` - -### From Source - -#### Requirements - -* [.NET Core 3.1.102 SDK](https://www.microsoft.com/net/download/dotnet-core/3.1#sdk-3.1.102) or +- [.NET Core 3.1.102 SDK](https://www.microsoft.com/net/download/dotnet-core/3.1#sdk-3.1.102) or newer patch release -* [Pester v5 PowerShell module, available on PowerShell Gallery](https://github.com/pester/Pester) -* [PlatyPS PowerShell module, available on PowerShell Gallery](https://github.com/PowerShell/platyPS/releases) -* Optionally but recommended for development: [Visual Studio 2017/2019](https://www.visualstudio.com/downloads/) +- [Pester v5 PowerShell module, available on PowerShell Gallery](https://github.com/pester/Pester) +- [PlatyPS PowerShell module, available on PowerShell Gallery](https://github.com/PowerShell/platyPS/releases) +- Optionally but recommended for development: [Visual Studio 2017/2019](https://www.visualstudio.com/downloads/) -#### Steps +### Steps -* Obtain the source +- Obtain the source - Download the latest source code from the [release page](https://github.com/PowerShell/PSScriptAnalyzer/releases) OR - Clone the repository (needs git) @@ -171,57 +86,57 @@ Exit git clone https://github.com/PowerShell/PSScriptAnalyzer ``` -* Navigate to the source directory +- Navigate to the source directory ```powershell cd path/to/PSScriptAnalyzer ``` -* Building You can either build using the `Visual Studio` solution `PSScriptAnalyzer.sln` or build +- Building You can either build using the `Visual Studio` solution `PSScriptAnalyzer.sln` or build using `PowerShell` specifically for your platform as follows: - * The default build is for the currently used version of PowerShell + - The default build is for the currently used version of PowerShell ```powershell .\build.ps1 ``` - * Windows PowerShell version 5.0 + - Windows PowerShell version 5.0 ```powershell .\build.ps1 -PSVersion 5 ``` - * Windows PowerShell version 4.0 + - Windows PowerShell version 4.0 ```powershell .\build.ps1 -PSVersion 4 ``` - * Windows PowerShell version 3.0 + - Windows PowerShell version 3.0 ```powershell .\build.ps1 -PSVersion 3 ``` - * PowerShell 7 + - PowerShell 7 ```powershell .\build.ps1 -PSVersion 7 ``` -* Rebuild documentation since it gets built automatically only the first time +- Rebuild documentation since it gets built automatically only the first time ```powershell .\build.ps1 -Documentation ``` -* Build all versions (PowerShell v3, v4, v5, and v6) and documentation +- Build all versions (PowerShell v3, v4, v5, and v6) and documentation ```powershell .\build.ps1 -All ``` -* Import the module +- Import the module ```powershell Import-Module .\out\PSScriptAnalyzer\PSScriptAnalyzer.psd1 @@ -230,7 +145,7 @@ Exit To confirm installation: run `Get-ScriptAnalyzerRule` in the PowerShell console to obtain the built-in rules. -* Adding/Removing resource strings +- Adding/Removing resource strings For adding/removing resource strings in the `*.resx` files, it is recommended to use `Visual Studio` since it automatically updates the strongly typed `*.Designer.cs` files. The @@ -239,11 +154,14 @@ built-in rules. `New-StronglyTypedCsFileForResx.ps1` script although the latter is discouraged since it leads to a bad diff of the `*.Designer.cs` files. -#### Tests +### Tests + Pester-based ScriptAnalyzer Tests are located in `path/to/PSScriptAnalyzer/Tests` folder. -* Ensure [Pester 4.3.1](https://www.powershellgallery.com/packages/Pester/4.3.1) or higher is installed -* In the root folder of your local repository, run: +- Ensure [Pester 4.3.1](https://www.powershellgallery.com/packages/Pester/4.3.1) or higher is + installed +- In the root folder of your local repository, run: + ```powershell ./build -Test ``` @@ -264,333 +182,22 @@ Get-TestFailures [Back to ToC](#table-of-contents) -## Parser Errors - -In prior versions of ScriptAnalyer, errors found during parsing were reported as errors and -diagnostic records were not created. ScriptAnalyzer now emits parser errors as diagnostic records in -the output stream with other diagnostic records. - -```powershell -PS> Invoke-ScriptAnalyzer -ScriptDefinition '"b" = "b"; function eliminate-file () { }' - -RuleName Severity ScriptName Line Message --------- -------- ---------- ---- ------- -InvalidLeftHandSide ParseError 1 The assignment expression is not - valid. The input to an - assignment operator must be an - object that is able to accept - assignments, such as a variable - or a property. -PSUseApprovedVerbs Warning 1 The cmdlet 'eliminate-file' uses an - unapproved verb. -``` - -The RuleName is set to the `ErrorId` of the parser error. - -If ParseErrors would like to be suppressed, do not include it as a value in the `-Severity` -parameter. - -```powershell -PS> Invoke-ScriptAnalyzer -ScriptDefinition '"b" = "b"; function eliminate-file () { }' -Severity Warning - -RuleName Severity ScriptName Line Message --------- -------- ---------- ---- ------- -PSUseApprovedVerbs Warning 1 The cmdlet 'eliminate-file' uses an - unapproved verb. -``` - -## Suppressing Rules - -You can suppress a rule by decorating a script/function or script/function parameter with .NET's -[SuppressMessageAttribute](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.suppressmessageattribute). -`SuppressMessageAttribute`'s constructor takes two parameters: a category and a check ID. Set the -`categoryID` parameter to the name of the rule you want to suppress and set the `checkID` parameter -to a null or empty string. You can optionally add a third named parameter with a justification for -suppressing the message: - -```powershell -function SuppressMe() -{ - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Justification='Just an example')] - param() - - Write-Verbose -Message "I'm making a difference!" - -} -``` - -All rule violations within the scope of the script/function/parameter you decorate will be -suppressed. - -To suppress a message on a specific parameter, set the `SuppressMessageAttribute`'s `CheckId` -parameter to the name of the parameter: - -```powershell -function SuppressTwoVariables() -{ - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'b')] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'a')] - param([string]$a, [int]$b) - { - } -} -``` - -Use the `SuppressMessageAttribute`'s `Scope` property to limit rule suppression to functions or -classes within the attribute's scope. - -Use the value `Function` to suppress violations on all functions within the attribute's scope. Use -the value `Class` to suppress violations on all classes within the attribute's scope: - -```powershell -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Scope='Function')] -param( -) - -function InternalFunction -{ - param() - - Write-Verbose -Message "I am invincible!" -} -``` - -You can further restrict suppression based on a function/parameter/class/variable/object's name by -setting the `SuppressMessageAttribute's` `Target` property to a regular expression or a glob -pattern. Few examples are given below. - -Suppress `PSAvoidUsingWriteHost` rule violation in `start-bar` and `start-baz` but not in -`start-foo` and `start-bam`: - -```powershell -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='start-ba[rz]')] -param() -function start-foo { - write-host "start-foo" -} - -function start-bar { - write-host "start-bar" -} - -function start-baz { - write-host "start-baz" -} - -function start-bam { - write-host "start-bam" -} -``` - -Suppress violations in all the functions: - -```powershell -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='*')] -Param() -``` - -Suppress violation in `start-bar`, `start-baz` and `start-bam` but not in `start-foo`: - -```powershell -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='start-b*')] -Param() -``` - -**Note**: Parser Errors cannot be suppressed via the `SuppressMessageAttribute` - -[Back to ToC](#table-of-contents) - -## Settings Support in ScriptAnalyzer - -Settings that describe ScriptAnalyzer rules to include/exclude based on `Severity` can be created -and supplied to `Invoke-ScriptAnalyzer` using the `Setting` parameter. This enables a user to create -a custom configuration for a specific environment. We support the following modes for specifying the -settings file. - -### Built-in Presets - -ScriptAnalyzer ships a set of built-in presets that can be used to analyze scripts. For example, if -the user wants to run *PowerShell Gallery* rules on their module, then they use the following -command. - -```powershell -PS> Invoke-ScriptAnalyzer -Path /path/to/module/ -Settings PSGallery -Recurse -``` - -Along with `PSGallery` there are a few other built-in presets, including, `DSC` and -`CodeFormatting`, that can be used. These presets can be tab completed for the `Settings` parameter. - -### Explicit - -The following example excludes two rules from the default set of rules and any rule that does not -output an Error or Warning diagnostic record. - -```powershell -# PSScriptAnalyzerSettings.psd1 -@{ - Severity=@('Error','Warning') - ExcludeRules=@('PSAvoidUsingCmdletAliases', - 'PSAvoidUsingWriteHost') -} -``` - -Then invoke that settings file when using `Invoke-ScriptAnalyzer`: - -```powershell -Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1 -``` - -The next example selects a few rules to execute instead of all the default rules. - -```powershell -# PSScriptAnalyzerSettings.psd1 -@{ - IncludeRules=@('PSAvoidUsingPlainTextForPassword', - 'PSAvoidUsingConvertToSecureStringWithPlainText') -} -``` - -Then invoke that settings file: - -```powershell -Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1 -``` - -### Implicit - -If you place a PSScriptAnayzer settings file named `PSScriptAnalyzerSettings.psd1` in your project -root, PSScriptAnalyzer will discover it if you pass the project root as the `Path` parameter. - -```powershell -Invoke-ScriptAnalyzer -Path "C:\path\to\project" -Recurse -``` - -Note that providing settings explicitly takes higher precedence over this implicit mode. Sample -settings files are provided -[here](https://github.com/PowerShell/PSScriptAnalyzer/tree/master/Engine/Settings). - -## Custom rules - -It is possible to provide one or more paths to custom rules in the settings file. It is important -that these paths either point to a module's folder (implicitly uses the module manifest) or to the -module's script file (.psm1). The module should export the custom rules (as functions) for them to -be available to PS Script Analyzer. - -In this example the property `CustomRulePath` points to two different modules. Both modules exports -the rules (the functions) with the verb `Measure` so that is used for the property `IncludeRules`. - -```powershell -@{ - CustomRulePath = @( - '.\output\RequiredModules\DscResource.AnalyzerRules' - '.\tests\QA\AnalyzerRules\SqlServerDsc.AnalyzerRules.psm1' - ) - - IncludeRules = @( - 'Measure-*' - ) -} -``` - -It is also possible to used default rules by adding those to `IncludeRules`. When including default -rules is important that the property `IncludeDefaultRules` is set to `$true` otherwise the default -rules will not be triggered. - -```powershell -@{ - CustomRulePath = @( - '.\output\RequiredModules\DscResource.AnalyzerRules' - '.\tests\QA\AnalyzerRules\SqlServerDsc.AnalyzerRules.psm1' - ) - - IncludeDefaultRules = $true - - IncludeRules = @( - # Default rules - 'PSAvoidDefaultValueForMandatoryParameter' - 'PSAvoidDefaultValueSwitchParameter' - - # Custom rules - 'Measure-*' - ) -} -``` - -### Using custom rules in Visual Studio Code - -It is also possible to use the custom rules that are provided in the settings file in Visual Studio -Code. This is done by adding a Visual Studio Code workspace settings file (`.vscode/settings.json`). - -```json -{ - "powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1", - "powershell.scriptAnalysis.enable": true, -} -``` - -[Back to ToC](#table-of-contents) - -## ScriptAnalyzer as a .NET library - -ScriptAnalyzer engine and functionality can now be directly consumed as a library. +## Using PSScriptAnalyzer -Here are the public interfaces: -``` c# -using Microsoft.Windows.PowerShell.ScriptAnalyzer; - -public void Initialize(System.Management.Automation.Runspaces.Runspace runspace, -Microsoft.Windows.PowerShell.ScriptAnalyzer.IOutputWriter outputWriter, -[string[] customizedRulePath = null], -[string[] includeRuleNames = null], -[string[] excludeRuleNames = null], -[string[] severity = null], -[bool suppressedOnly = false], -[string profile = null]) - -public System.Collections.Generic.IEnumerable AnalyzePath(string path, - [bool searchRecursively = false]) - -public System.Collections.Generic.IEnumerable GetRule(string[] moduleNames, string[] ruleNames) -``` - -[Back to ToC](#table-of-contents) - -## Violation Correction - -Some violations can be fixed by replacing the violation causing content with a suggested -alternative. You can use the `-Fix` switch to automatically apply the suggestions. Since -`Invoke-ScriptAnalyzer` implements `SupportsShouldProcess`, you can additionally use `-WhatIf` or -`-Confirm` to find out which corrections would be applied. It goes without saying that you should -use source control when applying those corrections since some some of them such as the one for -`AvoidUsingPlainTextForPassword` might require additional script modifications that cannot be made -automatically. Should your scripts be sensitive to encoding you should also check that because the -initial encoding can not be preserved in all cases. - -The initial motivation behind having the `SuggestedCorrections` property on the `ErrorRecord` (which -is how the `-Fix` switch works under the hood) was to enable quick-fix like scenarios in editors -like VSCode, Sublime, etc. At present, we provide valid `SuggestedCorrection` only for the following -rules, while gradually adding this feature to more rules. - -- AvoidAlias.cs -- AvoidUsingPlainTextForPassword.cs -- MisleadingBacktick.cs -- MissingModuleManifestField.cs -- UseToExportFieldsInManifest.cs - -[Back to ToC](#table-of-contents) +The documentation in this section can be found in +[Using PSScriptAnalyzer](https://docs.microsoft.com/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer). ## Contributions are welcome There are many ways to contribute: -1. Open a new bug report, feature request or just ask a question by opening a new issue [here]( - https://github.com/PowerShell/PSScriptAnalyzer/issues/new/choose). +1. Open a new bug report, feature request or just ask a question by opening a + [new issue](https://github.com/PowerShell/PSScriptAnalyzer/issues/new/choose). 2. Participate in the discussions of [issues](https://github.com/PowerShell/PSScriptAnalyzer/issues), - [pull requests](https://github.com/PowerShell/PSScriptAnalyzer/pulls) and verify/test fixes or - new features. -3. Submit your own fixes or features as a pull request but please discuss it beforehand in an issue - if the change is substantial. + [pull requests](https://github.com/PowerShell/PSScriptAnalyzer/pulls) and test fixes or new + features. +3. Submit your own fixes or features as a pull request but please discuss it beforehand in an issue. 4. Submit test cases. [Back to ToC](#table-of-contents) @@ -606,8 +213,8 @@ There are many ways to contribute: - Create a release build in `out/` ```powershell - PS> Import-Module .\Utils\ReleaseMaker.psm1 - PS> New-Release +Import-Module .\Utils\ReleaseMaker.psm1 +New-Release ``` - Sign the binaries and PowerShell files in the release build and publish the module to diff --git a/ScriptRuleDocumentation.md b/ScriptRuleDocumentation.md deleted file mode 100644 index 36979820a..000000000 --- a/ScriptRuleDocumentation.md +++ /dev/null @@ -1,208 +0,0 @@ -## Documentation for Customized Rules in PowerShell Scripts - -PSScriptAnalyzer uses MEF(Managed Extensibility Framework) to import all rules defined in the assembly. It can also consume rules written in PowerShell scripts. - -When calling Invoke-ScriptAnalyzer, users can specify custom rules using the parameter `CustomizedRulePath`. - -The purpose of this documentation is to serve as a basic guide on creating your own customized rules. - -### Basics - -- Functions should have comment-based help. Make sure .DESCRIPTION field is there, as it will be consumed as rule description for the customized rule. - -```powershell -<# -.SYNOPSIS - Name of your rule. -.DESCRIPTION - This would be the description of your rule. Please refer to Rule Documentation for consistent rule messages. -.EXAMPLE -.INPUTS -.OUTPUTS -.NOTES -#> -``` - -- Output type should be DiagnosticRecord: - -```powershell -[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] -``` - -- Make sure each function takes either a Token array or an Ast as a parameter. The _Ast_ parameter name must end with 'Ast' and the _Token_ parameter name must end with 'Token' - -```powershell -Param -( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.Language.ScriptBlockAst] - $testAst -) -``` - -```powershell -Param -( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.Language.Token[]] - $testToken -) -``` - -- DiagnosticRecord should have at least four properties: Message, Extent, RuleName and Severity - -```powershell -$result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{ - "Message" = "This is a sample rule" - "Extent" = $ast.Extent - "RuleName" = $PSCmdlet.MyInvocation.InvocationName - "Severity" = "Warning" -} -``` -Optionally, since version 1.17.0, a `SuggestedCorrections` property of type `IEnumerable` can also be added in script rules but care must be taken that the type is correct, an example is: -```powershell -[int]$startLineNumber = $ast.Extent.StartLineNumber -[int]$endLineNumber = $ast.Extent.EndLineNumber -[int]$startColumnNumber = $ast.Extent.StartColumnNumber -[int]$endColumnNumber = $ast.Extent.EndColumnNumber -[string]$correction = 'Correct text that replaces Extent text' -[string]$file = $MyInvocation.MyCommand.Definition -[string]$optionalDescription = 'Useful but optional description text' -$correctionExtent = New-Object 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' $startLineNumber,$endLineNumber,$startColumnNumber,$endColumnNumber,$correction,$description -$suggestedCorrections = New-Object System.Collections.ObjectModel.Collection['Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent'] -$suggestedCorrections.add($correctionExtent) | out-null - -[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ - "Message" = "This is a rule with a suggested correction" - "Extent" = $ast.Extent - "RuleName" = $PSCmdlet.MyInvocation.InvocationName - "Severity" = "Warning" - "Severity" = "Warning" - "RuleSuppressionID" = "MyRuleSuppressionID" - "SuggestedCorrections" = $suggestedCorrections -} -``` - -- Make sure you export the function(s) at the end of the script using Export-ModuleMember - -```powershell -Export-ModuleMember -Function (FunctionName) -``` - -### Example - -```powershell -<# - .SYNOPSIS - Uses #Requires -RunAsAdministrator instead of your own methods. - .DESCRIPTION - The #Requires statement prevents a script from running unless the Windows PowerShell version, modules, snap-ins, and module and snap-in version prerequisites are met. - From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator). - Script developers does not need to write their own methods any more. - To fix a violation of this rule, please consider to use #Requires -RunAsAdministrator instead of your own methods. - .EXAMPLE - Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst - .INPUTS - [System.Management.Automation.Language.ScriptBlockAst] - .OUTPUTS - [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES - None -#> -function Measure-RequiresRunAsAdministrator -{ - [CmdletBinding()] - [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] - Param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.Language.ScriptBlockAst] - $ScriptBlockAst - ) - - Process - { - $results = @() - try - { - #region Define predicates to find ASTs. - # Finds specific method, IsInRole. - [ScriptBlock]$predicate1 = { - param ([System.Management.Automation.Language.Ast]$Ast) - [bool]$returnValue = $false - if ($Ast -is [System.Management.Automation.Language.MemberExpressionAst]) - { - [System.Management.Automation.Language.MemberExpressionAst]$meAst = $Ast - if ($meAst.Member -is [System.Management.Automation.Language.StringConstantExpressionAst]) - { - [System.Management.Automation.Language.StringConstantExpressionAst]$sceAst = $meAst.Member - if ($sceAst.Value -eq 'isinrole') - { - $returnValue = $true - } - } - } - return $returnValue - } - - # Finds specific value, [system.security.principal.windowsbuiltinrole]::administrator. - [ScriptBlock]$predicate2 = { - param ([System.Management.Automation.Language.Ast]$Ast) - [bool]$returnValue = $false - if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst]) - { - [System.Management.Automation.Language.AssignmentStatementAst]$asAst = $Ast - if ($asAst.Right.ToString() -eq '[system.security.principal.windowsbuiltinrole]::administrator') - { - $returnValue = $true - } - } - return $returnValue - } - #endregion - #region Finds ASTs that match the predicates. - - [System.Management.Automation.Language.Ast[]]$methodAst = $ScriptBlockAst.FindAll($predicate1, $true) - [System.Management.Automation.Language.Ast[]]$assignmentAst = $ScriptBlockAst.FindAll($predicate2, $true) - if ($null -ne $ScriptBlockAst.ScriptRequirements) - { - if ((!$ScriptBlockAst.ScriptRequirements.IsElevationRequired) -and - ($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0)) - { - $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ - 'Message' = $Messages.MeasureRequiresRunAsAdministrator - 'Extent' = $assignmentAst.Extent - 'RuleName' = $PSCmdlet.MyInvocation.InvocationName - 'Severity' = 'Information' - } - $results += $result - } - } - else - { - if (($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0)) - { - $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ - 'Message' = $Messages.MeasureRequiresRunAsAdministrator - 'Extent' = $assignmentAst.Extent - 'RuleName' = $PSCmdlet.MyInvocation.InvocationName - 'Severity' = 'Information' - } - $results += $result - } - } - return $results - #endregion - } - catch - { - $PSCmdlet.ThrowTerminatingError($PSItem) - } - } -} -``` - -More examples can be found in *Tests\Engine\CommunityAnalyzerRules*