diff --git a/README.md b/README.md index aaaf09435..14c23f010 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ usage of Invoke-Expression etc. Additional functionalities such as exclude/inclu Usage ====================== -``` PowerShell +```powershell Get-ScriptAnalyzerRule [-CustomRulePath ] [-RecurseCustomRulePath] [-Name ] [-Severity ] [] Invoke-ScriptAnalyzer [-Path] [-CustomRulePath ] [-RecurseCustomRulePath] @@ -188,7 +188,7 @@ Pester-based ScriptAnalyzer Tests are located in `path/to/PSScriptAnalyzer/Tests * 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 +```powershell ./build -Test ``` @@ -251,7 +251,7 @@ 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 +```powershell function SuppressMe() { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Justification='Just an example')] @@ -265,7 +265,7 @@ function SuppressMe() 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 +```powershell function SuppressTwoVariables() { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'b')] @@ -280,7 +280,7 @@ Use the `SuppressMessageAttribute`'s `Scope` property to limit rule suppression 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 +```powershell [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Scope='Function')] param( ) @@ -296,7 +296,7 @@ function InternalFunction 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 +```powershell [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='start-ba[rz]')] param() function start-foo { @@ -317,13 +317,13 @@ function start-bam { ``` Suppress violations in all the functions: -``` PowerShell +```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 +```powershell [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='start-b*')] Param() ``` @@ -354,7 +354,7 @@ Along with `PSGallery` there are a few other built-in presets, including, `DSC` 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 +```powershell # PSScriptAnalyzerSettings.psd1 @{ Severity=@('Error','Warning') @@ -365,13 +365,13 @@ that does not output an Error or Warning diagnostic record. Then invoke that settings file when using `Invoke-ScriptAnalyzer`: -``` PowerShell +```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 +```powershell # PSScriptAnalyzerSettings.psd1 @{ IncludeRules=@('PSAvoidUsingPlainTextForPassword', @@ -380,7 +380,7 @@ The next example selects a few rules to execute instead of all the default rules ``` Then invoke that settings file: -``` PowerShell +```powershell Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1 ``` @@ -388,7 +388,7 @@ Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1 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 +```powershell Invoke-ScriptAnalyzer -Path "C:\path\to\project" -Recurse ``` diff --git a/RuleDocumentation/AlignAssignmentStatement.md b/RuleDocumentation/AlignAssignmentStatement.md index 1462bd035..948092848 100644 --- a/RuleDocumentation/AlignAssignmentStatement.md +++ b/RuleDocumentation/AlignAssignmentStatement.md @@ -4,9 +4,11 @@ ## Description -Consecutive assignment statements are more readable if they are aligned. By aligned, we imply that the `equal` sign for all the assignment statements should be in the same column. +Consecutive assignment statements are more readable if they are aligned. By aligned, we imply that +the `equal` sign for all the assignment statements should be in the same column. -The rule looks for key (property) value pairs in a hashtable (DSC configuration) to check if they are aligned or not. Consider the following example in which the key value pairs are not aligned. +The rule looks for key (property) value pairs in a hashtable (DSC configuration) to check if they +are aligned or not. Consider the following example in which the key value pairs are not aligned. ```powershell $hashtable = @{ @@ -24,17 +26,18 @@ $hashtable = @{ } ``` -The rule will ignore hashtables in which the assignment statements are on the same line. For example, the rule will ignore `$h = {a = 1; b = 2}`. +The rule ignores hashtables in which the assignment statements are on the same line. For example, +the rule ignores `$h = {a = 1; b = 2}`. ## Configuration ```powershell - Rules = @{ - PSAlignAssignmentStatement = @{ - Enable = $true - CheckHashtable = $true - } +Rules = @{ + PSAlignAssignmentStatement = @{ + Enable = $true + CheckHashtable = $true } +} ``` ### Parameters @@ -45,4 +48,6 @@ Enable or disable the rule during ScriptAnalyzer invocation. #### CheckHashtable: bool (Default value is `$false`) -Enforce alignment of assignment statements in a hashtable and in a DSC Configuration. There is only one switch for hasthable and DSC configuration because the property value pairs in a DSC configuration are parsed as key value pairs of a hashtable. +Enforce alignment of assignment statements in a hashtable and in a DSC Configuration. There is only +one switch for hasthable and DSC configuration because the property value pairs in a DSC +configuration are parsed as key-value pairs of a hashtable. diff --git a/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md b/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md index d9616e418..6d2f741e1 100644 --- a/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md +++ b/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md @@ -4,9 +4,11 @@ ## Description -`PowerShell` exposes some of its built-in variables that are known as automatic variables. Many of them are read-only and PowerShell would throw an error when trying to assign an value on those. Other automatic variables should only be assigned to in certain special cases to achieve a certain effect as a special technique. +PowerShell has built-in variables known as automatic variables. Many of them are read-only and +PowerShell throws an error when trying to assign an value on those. Other automatic variables should +only be assigned in certain special cases to achieve a certain effect as a special technique. -To understand more about automatic variables, see ```Get-Help about_Automatic_Variables```. +To understand more about automatic variables, see `Get-Help about_Automatic_Variables`. ## How @@ -16,18 +18,19 @@ Use variable names in functions or their parameters that do not conflict with au ### Wrong -The variable `$Error` is an automatic variables that exists in the global scope and should therefore never be used as a variable or parameter name. +The variable `$Error` is an automatic variables that exists in the global scope and should therefore +never be used as a variable or parameter name. -``` PowerShell +```powershell function foo($Error){ } ``` -``` PowerShell +```powershell function Get-CustomErrorMessage($ErrorMessage){ $Error = "Error occurred: $ErrorMessage" } ``` ### Correct -``` PowerShell +```powershell function Get-CustomErrorMessage($ErrorMessage){ $FinalErrorMessage = "Error occurred: $ErrorMessage" } ``` diff --git a/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md b/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md index 6b1a3eb57..9c45e53f2 100644 --- a/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md +++ b/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md @@ -4,13 +4,15 @@ ## Description -Mandatory parameters should not have a default values because there is no scenario where the default can be used because `PowerShell` will prompt anyway if the parameter value is not specified when calling the function. +Mandatory parameters should not have a default values because there is no scenario where the default +can be used. PowerShell prompts for a value if the parameter value is not specified when calling the +function. ## Example ### Wrong -``` PowerShell +```powershell function Test { @@ -25,7 +27,7 @@ function Test ### Correct -``` PowerShell +```powershell function Test { [CmdletBinding()] diff --git a/RuleDocumentation/AvoidDefaultValueSwitchParameter.md b/RuleDocumentation/AvoidDefaultValueSwitchParameter.md index bd1f3018d..428ff7d64 100644 --- a/RuleDocumentation/AvoidDefaultValueSwitchParameter.md +++ b/RuleDocumentation/AvoidDefaultValueSwitchParameter.md @@ -14,7 +14,7 @@ Change the default value of the switch parameter to be false. ### Wrong -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] @@ -32,7 +32,7 @@ function Test-Script ### Correct -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] diff --git a/RuleDocumentation/AvoidGlobalAliases.md b/RuleDocumentation/AvoidGlobalAliases.md index dd4bd3807..c4708c86a 100644 --- a/RuleDocumentation/AvoidGlobalAliases.md +++ b/RuleDocumentation/AvoidGlobalAliases.md @@ -4,11 +4,13 @@ ## Description -Globally scoped aliases override existing aliases within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules and scripts. +Globally scoped aliases override existing aliases within the sessions with matching names. This name +collision can cause difficult to debug issues for consumers of modules and scripts. -To understand more about scoping, see ```Get-Help about_Scopes```. +To understand more about scoping, see `Get-Help about_Scopes`. -**NOTE** This rule is not available in PowerShell version 3 and 4 due to the `StaticParameterBinder.BindCommand` API that the rule uses internally. +**NOTE** This rule is not available in PowerShell version 3 or 4 because it uses the +`StaticParameterBinder.BindCommand` API. ## How @@ -18,12 +20,12 @@ Use other scope modifiers for new aliases. ### Wrong -``` PowerShell +```powershell New-Alias -Name Name -Value Value -Scope "Global" ``` ### Correct -``` PowerShell +```powershell New-Alias -Name Name1 -Value Value ``` diff --git a/RuleDocumentation/AvoidGlobalFunctions.md b/RuleDocumentation/AvoidGlobalFunctions.md index a28c87f69..2d8a32b0a 100644 --- a/RuleDocumentation/AvoidGlobalFunctions.md +++ b/RuleDocumentation/AvoidGlobalFunctions.md @@ -4,10 +4,11 @@ ## Description -Globally scoped functions override existing functions within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules. +Globally scoped functions override existing functions within the sessions with matching names. This +name collision can cause difficult to debug issues for consumers of modules. -To understand more about scoping, see ```Get-Help about_Scopes```. +To understand more about scoping, see `Get-Help about_Scopes`. ## How @@ -17,12 +18,12 @@ Use other scope modifiers for functions. ### Wrong -``` PowerShell +```powershell function global:functionName {} ``` ### Correct -``` PowerShell -function functionName {} +```powershell +function functionName {} ``` diff --git a/RuleDocumentation/AvoidGlobalVars.md b/RuleDocumentation/AvoidGlobalVars.md index 12e02b92b..4de23cbe7 100644 --- a/RuleDocumentation/AvoidGlobalVars.md +++ b/RuleDocumentation/AvoidGlobalVars.md @@ -4,15 +4,17 @@ ## Description -A variable is a unit of memory in which values are stored. Windows PowerShell controls access to variables, functions, aliases, and drives through a mechanism known as scoping. -Variables and functions that are present when Windows PowerShell starts have been created in the global scope. +A variable is a unit of memory in which values are stored. PowerShell controls access to variables, +functions, aliases, and drives through a mechanism known as scoping. Variables and functions that +are present when PowerShell starts have been created in the global scope. Globally scoped variables include: -* Automatic variables -* Preference variables -* Variables, aliases, and functions that are in your Windows PowerShell profiles -To understand more about scoping, see ```Get-Help about_Scopes```. +- Automatic variables +- Preference variables +- Variables, aliases, and functions that are in your PowerShell profiles + +To understand more about scoping, see `Get-Help about_Scopes`. ## How @@ -22,20 +24,20 @@ Use other scope modifiers for variables. ### Wrong -``` PowerShell +```powershell $Global:var1 = $null function Test-NotGlobal ($var) { - $a = $var + $var1 + $a = $var + $var1 } ``` ### Correct -``` PowerShell +```powershell $var1 = $null function Test-NotGlobal ($var1, $var2) { - $a = $var1 + $var2 + $a = $var1 + $var2 } ``` diff --git a/RuleDocumentation/AvoidInvokingEmptyMembers.md b/RuleDocumentation/AvoidInvokingEmptyMembers.md index 814cc131e..e48aa42d6 100644 --- a/RuleDocumentation/AvoidInvokingEmptyMembers.md +++ b/RuleDocumentation/AvoidInvokingEmptyMembers.md @@ -4,7 +4,8 @@ ## Description -Invoking non-constant members can cause potential bugs. Please double check the syntax to make sure that invoked members are constants. +Invoking non-constant members can cause potential bugs. Please double check the syntax to make sure +that invoked members are constants. ## How @@ -14,14 +15,14 @@ Provide the requested members for a given type or class. ### Wrong -``` PowerShell +```powershell $MyString = "abc" $MyString.('len'+'gth') ``` ### Correct -``` PowerShell +```powershell $MyString = "abc" $MyString.('length') ``` diff --git a/RuleDocumentation/AvoidLongLines.md b/RuleDocumentation/AvoidLongLines.md index dfceb2717..b90929819 100644 --- a/RuleDocumentation/AvoidLongLines.md +++ b/RuleDocumentation/AvoidLongLines.md @@ -4,19 +4,20 @@ ## Description -Lines should be no longer than a configured number of characters (default: 120), including leading whitespace (indentation). +Lines should be no longer than a configured number of characters (default: 120), including leading +whitespace (indentation). **Note**: This rule is not enabled by default. The user needs to enable it through settings. ## Configuration ```powershell - Rules = @{ - PSAvoidLongLines = @{ - Enable = $true - MaximumLineLength = 120 - } +Rules = @{ + PSAvoidLongLines = @{ + Enable = $true + MaximumLineLength = 120 } +} ``` ### Parameters diff --git a/RuleDocumentation/AvoidMultipleTypeAttributes.md b/RuleDocumentation/AvoidMultipleTypeAttributes.md index 5143042a2..8e8209a9b 100644 --- a/RuleDocumentation/AvoidMultipleTypeAttributes.md +++ b/RuleDocumentation/AvoidMultipleTypeAttributes.md @@ -4,7 +4,8 @@ ## Description -Parameters should not have more than one type specifier. Multiple type specifiers on parameters will cause a runtime error. +Parameters should not have more than one type specifier. Multiple type specifiers on parameters +cause runtime errors. ## How @@ -14,7 +15,7 @@ Ensure each parameter has only 1 type specifier. ### Wrong -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] @@ -33,7 +34,7 @@ function Test-Script ### Correct -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] diff --git a/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md b/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md index a9e870660..2421acaa0 100644 --- a/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md +++ b/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md @@ -1,66 +1,66 @@ -# AvoidNullOrEmptyHelpMessageAttribute - -**Severity Level: Warning** - -## Description - -The value of the `HelpMessage` attribute should not be an empty string or a null value as this causes PowerShell's interpreter to throw an mirror when executing the -function or cmdlet. - -## How - -Specify a value for the `HelpMessage` attribute. - -## Example - -### Wrong - -``` PowerShell -Function BadFuncEmptyHelpMessageEmpty -{ - Param( - [Parameter(HelpMessage='')] - [String] - $Param - ) - - $Param -} - -Function BadFuncEmptyHelpMessageNull -{ - Param( - [Parameter(HelpMessage=$null)] - [String] - $Param - ) - - $Param -} - -Function BadFuncEmptyHelpMessageNoAssignment -{ - Param( - [Parameter(HelpMessage)] - [String] - $Param - ) - - $Param -} -``` - -### Correct - -``` PowerShell -Function GoodFuncHelpMessage -{ - Param( - [Parameter(HelpMessage='This is helpful')] - [String] - $Param - ) - - $Param -} -``` +# AvoidNullOrEmptyHelpMessageAttribute + +**Severity Level: Warning** + +## Description + +The value of the `HelpMessage` attribute should not be an empty string or a null value as this +causes PowerShell's interpreter to throw an error when executing the function or cmdlet. + +## How + +Specify a value for the `HelpMessage` attribute. + +## Example + +### Wrong + +```powershell +Function BadFuncEmptyHelpMessageEmpty +{ + Param( + [Parameter(HelpMessage='')] + [String] + $Param + ) + + $Param +} + +Function BadFuncEmptyHelpMessageNull +{ + Param( + [Parameter(HelpMessage=$null)] + [String] + $Param + ) + + $Param +} + +Function BadFuncEmptyHelpMessageNoAssignment +{ + Param( + [Parameter(HelpMessage)] + [String] + $Param + ) + + $Param +} +``` + +### Correct + +```powershell +Function GoodFuncHelpMessage +{ + Param( + [Parameter(HelpMessage='This is helpful')] + [String] + $Param + ) + + $Param +} +``` diff --git a/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md b/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md index 1a4610eb7..8a8ed8ec4 100644 --- a/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md +++ b/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md @@ -4,14 +4,18 @@ ## Description -This rule flags cmdlets that are available in a given edition/version of PowerShell on a given operating system which are overwritten by a function declaration. It works by comparing function declarations against a set of allowlists which ship with PSScriptAnalyzer. These allowlist files are used by other PSScriptAnalyzer rules. More information can be found in the documentation for the [UseCompatibleCmdlets](./UseCompatibleCmdlets.md) rule. +This rule flags cmdlets that are available in a given edition/version of PowerShell on a given +operating system which are overwritten by a function declaration. It works by comparing function +declarations against a set of allowlists that ship with PSScriptAnalyzer. These allowlist files are +used by other PSScriptAnalyzer rules. More information can be found in the documentation for the +[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) rule. ## Configuration -To enable the rule to check if your script is compatible on PowerShell Core on Windows, put the following your settings file. +To enable the rule to check if your script is compatible on PowerShell Core on Windows, put the +following your settings file. - -```PowerShell +```powershell @{ 'Rules' = @{ 'PSAvoidOverwritingBuiltInCmdlets' = @{ @@ -27,7 +31,14 @@ To enable the rule to check if your script is compatible on PowerShell Core on W The parameter `PowerShellVersion` is a list of allowlists that ship with PSScriptAnalyzer. -**Note**: The default value for `PowerShellVersion` is `"core-6.1.0-windows"` if PowerShell 6 or later is installed, and `"desktop-5.1.14393.206-windows"` if it is not. - -Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major and minor versions of PowerShell are supplied. One can also create a custom settings file as well with the [New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) script and use it by placing the created `JSON` into the `Settings` folder of the `PSScriptAnalyzer` module installation folder, then the `PowerShellVersion` parameter is just its file name (that can also be changed if desired). -Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached it's end of life. +**Note**: The default value for `PowerShellVersion` is `"core-6.1.0-windows"` if PowerShell 6 or +later is installed, and `"desktop-5.1.14393.206-windows"` if it is not. + +Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major +and minor versions of PowerShell are supplied. One can also create a custom settings file as well +with the +[New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) +script and use it by placing the created `JSON` into the `Settings` folder of the `PSScriptAnalyzer` +module installation folder, then the `PowerShellVersion` parameter is just its file name (that can +also be changed if desired). Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer +1.18 since PowerShell 6.0 reached end of life. diff --git a/RuleDocumentation/AvoidShouldContinueWithoutForce.md b/RuleDocumentation/AvoidShouldContinueWithoutForce.md index 546fac7d8..fd27a1979 100644 --- a/RuleDocumentation/AvoidShouldContinueWithoutForce.md +++ b/RuleDocumentation/AvoidShouldContinueWithoutForce.md @@ -6,7 +6,8 @@ Functions that use ShouldContinue should have a boolean force parameter to allow user to bypass it. -You can get more details by running `Get-Help about_Functions_CmdletBindingAttribute` and `Get-Help about_Functions_Advanced_Methods` command in Windows PowerShell. +You can get more details by running `Get-Help about_Functions_CmdletBindingAttribute` and +`Get-Help about_Functions_Advanced_Methods` command in PowerShell. ## How @@ -16,7 +17,7 @@ Call the `ShouldContinue` method in advanced functions when `ShouldProcess` meth ### Wrong -``` PowerShell +```powershell Function Test-ShouldContinue { [CmdletBinding(SupportsShouldProcess=$true)] @@ -26,7 +27,7 @@ Function Test-ShouldContinue ) if ($PsCmdlet.ShouldContinue("ShouldContinue Query", "ShouldContinue Caption")) - { + { ... } } @@ -34,7 +35,7 @@ Function Test-ShouldContinue ### Correct -``` PowerShell +```powershell Function Test-ShouldContinue { [CmdletBinding(SupportsShouldProcess=$true)] @@ -45,7 +46,7 @@ Function Test-ShouldContinue ) if ($Force -or $PsCmdlet.ShouldContinue("ShouldContinue Query", "ShouldContinue Caption")) - { + { ... } } diff --git a/RuleDocumentation/AvoidTrailingWhitespace.md b/RuleDocumentation/AvoidTrailingWhitespace.md index 8a5a1e189..8e805b25b 100644 --- a/RuleDocumentation/AvoidTrailingWhitespace.md +++ b/RuleDocumentation/AvoidTrailingWhitespace.md @@ -4,4 +4,5 @@ ## Description -Lines should not end with whitespace characters. This can cause problems with the line-continuation backtick, and also clutters up future commits to source control. +Lines should not end with whitespace characters. This can cause problems with the line-continuation +backtick, and also clutters up future commits to source control. diff --git a/RuleDocumentation/AvoidUsingCmdletAliases.md b/RuleDocumentation/AvoidUsingCmdletAliases.md index 46fcd2f2a..691986e5b 100644 --- a/RuleDocumentation/AvoidUsingCmdletAliases.md +++ b/RuleDocumentation/AvoidUsingCmdletAliases.md @@ -4,15 +4,20 @@ ## Description -An alias is an alternate name or nickname for a CMDLet or for a command element, such as a function, script, file, or executable file. -You can use the alias instead of the command name in any Windows PowerShell commands. There are also implicit aliases: When PowerShell cannot find the cmdlet name, it will try to append `Get-` to the command as a last resort before, therefore e.g. `verb` will execute `Get-Verb`. +An alias is an alternate name or nickname for a cmdlet or for a command element, such as a function, +script, file, or executable file. You can use the alias instead of the command name in any +PowerShell commands. -Every PowerShell author learns the actual command names, but different authors learn and use different aliases. Aliases can make code difficult to read, understand and -impact availability. +There are also implicit aliases. When PowerShell cannot find the cmdlet name, it will try to append +`Get-` to the command as a last resort. Therefore using the command `verb` will execute `Get-Verb`. -When developing PowerShell content that will potentially need to be maintained over time, either by the original author or others, you should use full command names. +Every PowerShell author learns the actual command names, but different authors learn and use +different aliases. Aliases can make code difficult to read, understand and impact availability. -The use of full command names also allows for syntax highlighting in sites and applications like GitHub and Visual Studio Code. +Using the full command name makes it eaiser to maintain your scripts in the the future. + +Using the full command names also allows for syntax highlighting in sites and applications like +GitHub and Visual Studio Code. ## How to Fix @@ -20,9 +25,12 @@ Use the full cmdlet name and not an alias. ## Alias Allowlist -To prevent `PSScriptAnalyzer` from flagging your preferred aliases, create an allowlist of the aliases in your settings file and point `PSScriptAnalyzer` to use the settings file. For example, to disable `PSScriptAnalyzer` from flagging `cd`, which is an alias of `Set-Location`, set the settings file content to the following. +To prevent `PSScriptAnalyzer` from flagging your preferred aliases, create an allowlist of the +aliases in your settings file and point `PSScriptAnalyzer` to use the settings file. For example, to +disable `PSScriptAnalyzer` from flagging `cd`, which is an alias of `Set-Location`, set the settings +file content to the following. -```PowerShell +```powershell # PSScriptAnalyzerSettings.psd1 @{ @@ -36,14 +44,14 @@ To prevent `PSScriptAnalyzer` from flagging your preferred aliases, create an al ## Example -### Wrong? +### Wrong -``` PowerShell +```powershell gps | Where-Object {$_.WorkingSet -gt 20000000} ``` -### Correct: +### Correct -``` PowerShell +```powershell Get-Process | Where-Object {$_.WorkingSet -gt 20000000} ``` diff --git a/RuleDocumentation/AvoidUsingComputerNameHardcoded.md b/RuleDocumentation/AvoidUsingComputerNameHardcoded.md index 740d24595..995c69b75 100644 --- a/RuleDocumentation/AvoidUsingComputerNameHardcoded.md +++ b/RuleDocumentation/AvoidUsingComputerNameHardcoded.md @@ -4,7 +4,8 @@ ## Description -The names of computers should never be hard coded as this will expose sensitive information. The `ComputerName` parameter should never have a hard coded value. +The names of computers should never be hard coded as this will expose sensitive information. The +`ComputerName` parameter should never have a hard coded value. ## How @@ -14,19 +15,19 @@ Remove hard coded computer names. ### Wrong -``` PowerShell +```powershell Function Invoke-MyRemoteCommand () { - Invoke-Command -Port 343 -ComputerName "hardcoderemotehostname" + Invoke-Command -Port 343 -ComputerName "hardcoderemotehostname" } ``` ### Correct -``` PowerShell +```powershell Function Invoke-MyCommand ($ComputerName) { - Invoke-Command -Port 343 -ComputerName $ComputerName + Invoke-Command -Port 343 -ComputerName $ComputerName } ``` @@ -34,18 +35,18 @@ Function Invoke-MyCommand ($ComputerName) ### Wrong -``` PowerShell +```powershell Function Invoke-MyLocalCommand () { - Invoke-Command -Port 343 -ComputerName "hardcodelocalhostname" + Invoke-Command -Port 343 -ComputerName "hardcodelocalhostname" } ``` ### Correct -``` PowerShell +```powershell Function Invoke-MyLocalCommand () { - Invoke-Command -Port 343 -ComputerName $env:COMPUTERNAME + Invoke-Command -Port 343 -ComputerName $env:COMPUTERNAME } ``` diff --git a/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md b/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md index e6af00af1..9c400c5f8 100644 --- a/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md +++ b/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md @@ -4,7 +4,8 @@ ## Description -The use of the `AsPlainText` parameter with the `ConvertTo-SecureString` command can expose secure information. +The use of the `AsPlainText` parameter with the `ConvertTo-SecureString` command can expose secure +information. ## How @@ -12,21 +13,24 @@ Use a standard encrypted variable to perform any SecureString conversions. ## Recommendations -If you do need an ability to retrieve the password from somewhere without prompting the user, consider using Windows Credential Store as used in the BetterCredentials module ( https://www.powershellgallery.com/packages/BetterCredentials/4.4/Content/BetterCredentials.psm1). If that does not work, consider using Azure KeyVault (https://azure.microsoft.com/en-us/services/key-vault/) or AWS KMS (https://aws.amazon.com/kms/). +If you do need an ability to retrieve the password from somewhere without prompting the user, +consider using the +[SecretStore](https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretStore) +module from the PowerShell Gallery. ## Example ### Wrong -``` PowerShell +```powershell $UserInput = Read-Host "Please enter your secure code" $EncryptedInput = ConvertTo-SecureString -String $UserInput -AsPlainText -Force ``` ### Correct -``` PowerShell +```powershell $SecureUserInput = Read-Host "Please enter your secure code" -AsSecureString $EncryptedInput = ConvertFrom-SecureString -String $SecureUserInput -$SecureString = Convertto-SecureString -String $EncryptedInput +$SecureString = ConvertTo-SecureString -String $EncryptedInput ``` diff --git a/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md b/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md index a814ea205..c65041e6b 100644 --- a/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md +++ b/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md @@ -4,7 +4,7 @@ ## Description -In PowerShell 5.0, a number of fields in module manifest files (.psd1) have been changed. +In PowerShell 5.0, a number of fields in module manifest files (`.psd1`) have been changed. The field `ModuleToProcess` has been replaced with the `RootModule` field. @@ -16,7 +16,7 @@ Replace `ModuleToProcess` with `RootModule` in the module manifest. ### Wrong -``` PowerShell +```powershell ModuleToProcess ='psscriptanalyzer' ModuleVersion = '1.0' @@ -24,7 +24,7 @@ ModuleVersion = '1.0' ### Correct -``` PowerShell +```powershell RootModule ='psscriptanalyzer' ModuleVersion = '1.0' diff --git a/RuleDocumentation/AvoidUsingDoubleQuotesForConstantString.md b/RuleDocumentation/AvoidUsingDoubleQuotesForConstantString.md index ec6813b86..f18361718 100644 --- a/RuleDocumentation/AvoidUsingDoubleQuotesForConstantString.md +++ b/RuleDocumentation/AvoidUsingDoubleQuotesForConstantString.md @@ -4,18 +4,27 @@ ## Description -When the value of a string is constant (i.e. not being interpolated by injecting variables or expression into such as e.g. `"$PID-$(hostname)"`), then single quotes should be used to express the constant nature of the string. This is not only to make the intent clearer that the string is a constant and makes it easier to use some special characters such as e.g. `$` within that string expression without the need to escape them. There are exceptions to that when double quoted strings are more readable though, e.g. when the string value itself has to contain a single quote (which would require a double single quotes to escape the character itself) or certain very special characters such as e.g. `"\n"` are already being escaped, the rule would not warn in this case as it is up to the author to decide on what is more readable in those cases. +Single quotes should be used when the value of a string is constant. A constant string doesn't +contain variables or expressions intended to insert values into the string, such as +`"$PID-$(hostname)"`). + +This makes the intent clearer that the string is a constant and makes it easier to use some special +characters such as `$` within that string expression without needing to escape them. + +There are exceptions to that when double quoted strings are more readable. For example, when the +string value itself must contain a single quote or other special characters, such as newline +(`` "`n" ``), are already being escaped. The rule does not warn in these cases. ## Example ### Wrong -``` PowerShell +```powershell $constantValue = "I Love PowerShell" ``` ### Correct -``` PowerShell +```powershell $constantValue = 'I Love PowerShell' ``` diff --git a/RuleDocumentation/AvoidUsingEmptyCatchBlock.md b/RuleDocumentation/AvoidUsingEmptyCatchBlock.md index b08930259..474db4d1c 100644 --- a/RuleDocumentation/AvoidUsingEmptyCatchBlock.md +++ b/RuleDocumentation/AvoidUsingEmptyCatchBlock.md @@ -4,22 +4,21 @@ ## Description -Empty catch blocks are considered a poor design choice as they result in the errors occurring in a `try` block not being acted upon. - -While this does not inherently lead to issues, they should be avoided wherever possible. +Empty catch blocks are considered a poor design choice because any errors occurring in a +`try` block cannot be handled. ## How -Use ```Write-Error``` or ```throw``` statements within the catch block. +Use `Write-Error` or `throw` statements within the catch block. ## Example ### Wrong -``` PowerShell +```powershell try { - 1/0 + 1/0 } catch [DivideByZeroException] { @@ -28,22 +27,22 @@ catch [DivideByZeroException] ### Correct -``` PowerShell +```powershell try { - 1/0 + 1/0 } catch [DivideByZeroException] { - Write-Error "DivideByZeroException" + Write-Error "DivideByZeroException" } try { - 1/0 + 1/0 } catch [DivideByZeroException] { - Throw "DivideByZeroException" + throw "DivideByZeroException" } ``` diff --git a/RuleDocumentation/AvoidUsingInvokeExpression.md b/RuleDocumentation/AvoidUsingInvokeExpression.md index 08329df75..3008f0cab 100644 --- a/RuleDocumentation/AvoidUsingInvokeExpression.md +++ b/RuleDocumentation/AvoidUsingInvokeExpression.md @@ -4,9 +4,11 @@ ## Description -Care must be taken when using the `Invoke-Expression` command. The `Invoke-Expression` executes the specified string and returns the results. +Care must be taken when using the `Invoke-Expression` command. The `Invoke-Expression` executes the +specified string and returns the results. -Code injection into your application or script can occur if the expression passed as a string includes any data provided from the user. +Code injection into your application or script can occur if the expression passed as a string +includes any data provided from the user. ## How @@ -16,12 +18,12 @@ Remove the use of `Invoke-Expression`. ### Wrong -``` PowerShell +```powershell Invoke-Expression "Get-Process" ``` ### Correct -``` PowerShell +```powershell Get-Process ``` diff --git a/RuleDocumentation/AvoidUsingPlainTextForPassword.md b/RuleDocumentation/AvoidUsingPlainTextForPassword.md index b9e4bffb8..793d12113 100644 --- a/RuleDocumentation/AvoidUsingPlainTextForPassword.md +++ b/RuleDocumentation/AvoidUsingPlainTextForPassword.md @@ -4,28 +4,30 @@ ## Description -Password parameters that take in plaintext will expose passwords and compromise the security of your system. Passwords should be stored in the -```SecureString``` type. +Password parameters that take in plaintext will expose passwords and compromise the security of your +system. Passwords should be stored in the **SecureString** type. The following parameters are considered password parameters (this is not case sensitive): -* Password -* Pass -* Passwords -* Passphrase -* Passphrases -* PasswordParam -If a parameter is defined with a name in the above list, it should be declared with type ```SecureString``` +- Password +- Pass +- Passwords +- Passphrase +- Passphrases +- PasswordParam + +If a parameter is defined with a name in the above list, it should be declared with type +**SecureString**. ## How -Change the type to ```SecureString```. +Change the type to **SecureString**. ## Example ### Wrong -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] @@ -40,7 +42,7 @@ function Test-Script ### Correct -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] diff --git a/RuleDocumentation/AvoidUsingPositionalParameters.md b/RuleDocumentation/AvoidUsingPositionalParameters.md index fc31c0de7..f1169aa5c 100644 --- a/RuleDocumentation/AvoidUsingPositionalParameters.md +++ b/RuleDocumentation/AvoidUsingPositionalParameters.md @@ -4,11 +4,14 @@ ## Description -When developing PowerShell content that will potentially need to be maintained over time, either by the original author or others, you should use full command names and parameter names. +Using positional parameters reduces the readability of code and can introduce errors. It is possible +that a future version of the cmdlet could change in a way that would break existing scripts if calls +to the cmdlet rely on the position of the parameters. -The use of positional parameters can reduce the readability of code and potentially introduce errors. Furthermore it is possible that future signatures of a Cmdlet could change in a way that would break existing scripts if calls to the Cmdlet rely on the position of the parameters. - -For simple Cmdlets with only a few positional parameters, the risk is much smaller and in order for this rule to be not too noisy, this rule gets only triggered when there are 3 or more parameters supplied. A simple example where the risk of using positional parameters is negligible, is e.g. `Test-Path $Path`. +For simple cmdlets with only a few positional parameters, the risk is much smaller. To prevent this +rule from being too noisy, this rule gets only triggered when there are 3 or more parameters +supplied. A simple example where the risk of using positional parameters is negligible, is +`Test-Path $Path`. ## How @@ -18,12 +21,12 @@ Use full parameter names when calling commands. ### Wrong -``` PowerShell -Get-Command Get-ChildItem Microsoft.PowerShell.Management System.Management.Automation.Cmdlet +```powershell +Get-Command ChildItem Microsoft.PowerShell.Management ``` ### Correct -``` PowerShell -Get-Command -Noun Get-ChildItem -Module Microsoft.PowerShell.Management -ParameterType System.Management.Automation.Cmdlet +```powershell +Get-Command -Noun ChildItem -Module Microsoft.PowerShell.Management ``` diff --git a/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md b/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md index 747cf2ca5..9ab524d73 100644 --- a/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md +++ b/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md @@ -4,17 +4,18 @@ ## Description -To standardize command parameters, credentials should be accepted as objects of type ```PSCredential```. Functions should not make use of username or password parameters. +To standardize command parameters, credentials should be accepted as objects of type +**PSCredential**. Functions should not make use of username or password parameters. ## How -Change the parameter to type ```PSCredential```. +Change the parameter to type **PSCredential**. ## Example ### Wrong -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] @@ -31,7 +32,7 @@ function Test-Script ### Correct -``` PowerShell +```powershell function Test-Script { [CmdletBinding()] diff --git a/RuleDocumentation/AvoidUsingWMICmdlet.md b/RuleDocumentation/AvoidUsingWMICmdlet.md index 379c94822..7e9ffa390 100644 --- a/RuleDocumentation/AvoidUsingWMICmdlet.md +++ b/RuleDocumentation/AvoidUsingWMICmdlet.md @@ -7,42 +7,46 @@ As of PowerShell 3.0, the CIM cmdlets should be used over the WMI cmdlets. The following cmdlets should not be used: -* `Get-WmiObject` -* `Remove-WmiObject` -* `Invoke-WmiObject` -* `Register-WmiEvent` -* `Set-WmiInstance` + +- `Get-WmiObject` +- `Remove-WmiObject` +- `Invoke-WmiObject` +- `Register-WmiEvent` +- `Set-WmiInstance` Use the following cmdlets instead: -* `Get-CimInstance` -* `Remove-CimInstance` -* `Invoke-CimMethod` -* `Register-CimIndicationEvent` -* `Set-CimInstance` -The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, allowing for the management of Windows and non-Windows operating systems. +- `Get-CimInstance` +- `Remove-CimInstance` +- `Invoke-CimMethod` +- `Register-CimIndicationEvent` +- `Set-CimInstance` + +The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model +(CIM) standard, allowing for the management of Windows and non-Windows operating systems. ## How Change to the equivalent CIM based cmdlet. -* `Get-WmiObject` -> `Get-CimInstance` -* `Remove-WmiObject` -> `Remove-CimInstance` -* `Invoke-WmiObject` -> `Invoke-CimMethod` -* `Register-WmiEvent` -> `Register-CimIndicationEvent` -* `Set-WmiInstance` -> `Set-CimInstance` + +- `Get-WmiObject` -> `Get-CimInstance` +- `Remove-WmiObject` -> `Remove-CimInstance` +- `Invoke-WmiObject` -> `Invoke-CimMethod` +- `Register-WmiEvent` -> `Register-CimIndicationEvent` +- `Set-WmiInstance` -> `Set-CimInstance` ## Example ### Wrong -``` PowerShell +```powershell Get-WmiObject -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-WmiObject Invoke-WmiMethod ?Class Win32_Process ?Name "Create" ?ArgumentList @{ CommandLine = "notepad.exe" } ``` ### Correct -``` PowerShell +```powershell Get-CimInstance -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-CIMInstance Invoke-CimMethod ?ClassName Win32_Process ?MethodName "Create" ?Arguments @{ CommandLine = "notepad.exe" } ``` diff --git a/RuleDocumentation/AvoidUsingWriteHost.md b/RuleDocumentation/AvoidUsingWriteHost.md index e109be908..0322fc564 100644 --- a/RuleDocumentation/AvoidUsingWriteHost.md +++ b/RuleDocumentation/AvoidUsingWriteHost.md @@ -4,39 +4,40 @@ ## Description -The use of `Write-Host` is greatly discouraged unless in the use of commands with the `Show` verb. The `Show` verb explicitly means "show on the screen, with no -other possibilities". +The use of `Write-Host` is greatly discouraged unless in the use of commands with the `Show` verb. +The `Show` verb explicitly means "show on the screen, with no other possibilities". Commands with the `Show` verb do not have this check applied. ## How -Replace `Write-Host` with `Write-Output` or `Write-Verbose` depending on whether the intention is logging or returning one or multiple objects. +Replace `Write-Host` with `Write-Output` or `Write-Verbose` depending on whether the intention is +logging or returning one or more objects. ## Example ### Wrong -``` PowerShell +```powershell function Get-MeaningOfLife { - ... - Write-Host "Computing the answer to the ultimate question of life, the universe and everything" - ... - Write-Host 42 + ... + Write-Host "Computing the answer to the ultimate question of life, the universe and everything" + ... + Write-Host 42 } ``` ### Correct -``` PowerShell +```powershell function Get-MeaningOfLife { - [CmdletBinding()]Param() # to make it possible to set the VerbosePreference when calling the function - ... - Write-Verbose "Computing the answer to the ultimate question of life, the universe and everything" - ... - Write-Output 42 + [CmdletBinding()]Param() # to make it possible to set the VerbosePreference when calling the function + ... + Write-Verbose "Computing the answer to the ultimate question of life, the universe and everything" + ... + Write-Output 42 } function Show-Something diff --git a/RuleDocumentation/DSCDscExamplesPresent.md b/RuleDocumentation/DSCDscExamplesPresent.md index 914a76107..8fc0cc475 100644 --- a/RuleDocumentation/DSCDscExamplesPresent.md +++ b/RuleDocumentation/DSCDscExamplesPresent.md @@ -8,44 +8,50 @@ Checks that DSC examples for given resource are present. ## How -To fix a violation of this rule, please make sure Examples directory is present: -* For non-class based resources it should exist at the same folder level as DSCResources folder. -* For class based resources it should be present at the same folder level as resource psm1 file. +To fix a violation of this rule, please make sure `Examples` directory is present: -Examples folder should contain sample configuration for given resource - file name should contain resource's name. +- For non-class based resources it should exist at the same folder level as `DSCResources` folder. +- For class based resources it should be present at the same folder level as resource `.psm1` file. + +The `Examples` folder should contain a sample configuration for given resource. The filename should +contain the resource's name. ## Example ### Non-class based resource Let's assume we have non-class based resource with a following file structure: -* xAzure - * DSCResources - * MSFT_xAzureSubscription - * MSFT_xAzureSubscription.psm1 - * MSFT_xAzureSubscription.schema.mof + +- xAzure + - DSCResources + - MSFT_xAzureSubscription + - MSFT_xAzureSubscription.psm1 + - MSFT_xAzureSubscription.schema.mof In this case, to fix this warning, we should add examples in a following way: -* xAzure - * DSCResources - * MSFT_xAzureSubscription - * MSFT_xAzureSubscription.psm1 - * MSFT_xAzureSubscription.schema.mof - * Examples - * MSFT_xAzureSubscription_AddSubscriptionExample.ps1 - * MSFT_xAzureSubscription_RemoveSubscriptionExample.ps1 + +- xAzure + - DSCResources + - MSFT_xAzureSubscription + - MSFT_xAzureSubscription.psm1 + - MSFT_xAzureSubscription.schema.mof + - Examples + - MSFT_xAzureSubscription_AddSubscriptionExample.ps1 + - MSFT_xAzureSubscription_RemoveSubscriptionExample.ps1 ### Class based resource Let's assume we have class based resource with a following file structure: -* MyDscResource - * MyDscResource.psm1 - * MyDscResource.psd1 + +- MyDscResource + - MyDscResource.psm1 + - MyDscResource.psd1 In this case, to fix this warning, we should add examples in a following way: -* MyDscResource - * MyDscResource.psm1 - * MyDscResource.psd1 - * Examples - * MyDscResource_Example1.ps1 - * MyDscResource_Example2.ps1 + +- MyDscResource + - MyDscResource.psm1 + - MyDscResource.psd1 + - Examples + - MyDscResource_Example1.ps1 + - MyDscResource_Example2.ps1 diff --git a/RuleDocumentation/DSCDscTestsPresent.md b/RuleDocumentation/DSCDscTestsPresent.md index a988d6b5d..4cec783c4 100644 --- a/RuleDocumentation/DSCDscTestsPresent.md +++ b/RuleDocumentation/DSCDscTestsPresent.md @@ -8,42 +8,48 @@ Checks that DSC tests for given resource are present. ## How -To fix a violation of this rule, please make sure Tests directory is present: -* For non-class based resources it should exist at the same folder level as DSCResources folder. -* For class based resources it should be present at the same folder level as resource psm1 file. +To fix a violation of this rule, please make sure `Tests` directory is present: -Tests folder should contain test script for given resource - file name should contain resource's name. +- For non-class based resources it should exist at the same folder level as `DSCResources` folder. +- For class based resources it should be present at the same folder level as resource `.psm1` file. + +The `Tests` folder should contain test script for given resource. The filename should contain the +resource's name. ## Example ### Non-class based resource Let's assume we have non-class based resource with a following file structure: -* xAzure - * DSCResources - * MSFT_xAzureSubscription - * MSFT_xAzureSubscription.psm1 - * MSFT_xAzureSubscription.schema.mof + +- xAzure + - DSCResources + - MSFT_xAzureSubscription + - MSFT_xAzureSubscription.psm1 + - MSFT_xAzureSubscription.schema.mof In this case, to fix this warning, we should add tests in a following way: -* xAzure - * DSCResources - * MSFT_xAzureSubscription - * MSFT_xAzureSubscription.psm1 - * MSFT_xAzureSubscription.schema.mof - * Tests - * MSFT_xAzureSubscription_Tests.ps1 + +- xAzure + - DSCResources + - MSFT_xAzureSubscription + - MSFT_xAzureSubscription.psm1 + - MSFT_xAzureSubscription.schema.mof + - Tests + - MSFT_xAzureSubscription_Tests.ps1 ### Class based resource Let's assume we have class based resource with a following file structure: -* MyDscResource - * MyDscResource.psm1 - * MyDscResource.psd1 + +- MyDscResource + - MyDscResource.psm1 + - MyDscResource.psd1 In this case, to fix this warning, we should add tests in a following way: -* MyDscResource - * MyDscResource.psm1 - * MyDscResource.psd1 - * Tests - * MyDscResource_Tests.ps1 + +- MyDscResource + - MyDscResource.psm1 + - MyDscResource.psd1 + - Tests + - MyDscResource_Tests.ps1 diff --git a/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md b/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md index f41e242e8..2f4574caa 100644 --- a/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md +++ b/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md @@ -7,14 +7,16 @@ The functions in DSC resources have specific return objects. For non-class based resources: -* `Set-TargetResource` must not return any value. -* `Test-TargetResource` must return a boolean. -* `Get-TargetResource` must return a hash table. + +- `Set-TargetResource` must not return any value. +- `Test-TargetResource` must return a boolean. +- `Get-TargetResource` must return a hash table. For class based resources: -* `Set` must not return any value. -* `Test` must return a boolean. -* `Get` must return an instance of the DSC class. + +- `Set` must not return any value. +- `Test` must return a boolean. +- `Get` must return an instance of the DSC class. ## How @@ -24,7 +26,7 @@ Ensure that each function returns the correct type. ### Wrong -``` PowerShell +```powershell function Get-TargetResource { param @@ -61,7 +63,7 @@ function Test-TargetResource ### Correct -``` PowerShell +```powershell function Get-TargetResource { [OutputType([Hashtable])] @@ -102,7 +104,7 @@ function Test-TargetResource ### Wrong -``` PowerShell +```powershell [DscResource()] class MyDSCResource { @@ -128,7 +130,7 @@ class MyDSCResource ### Correct -``` PowerShell +```powershell [DscResource()] class MyDSCResource { diff --git a/RuleDocumentation/DSCStandardDSCFunctionsInResource.md b/RuleDocumentation/DSCStandardDSCFunctionsInResource.md index ad37f69c8..a1bfa20be 100644 --- a/RuleDocumentation/DSCStandardDSCFunctionsInResource.md +++ b/RuleDocumentation/DSCStandardDSCFunctionsInResource.md @@ -7,14 +7,16 @@ All DSC resources are required to implement the correct functions. For non-class based resources: -* `Set-TargetResource` -* `Test-TargetResource` -* `Get-TargetResource` + +- `Set-TargetResource` +- `Test-TargetResource` +- `Get-TargetResource` For class based resources: -* `Set` -* `Test` -* `Get` + +- `Set` +- `Test` +- `Get` ## How @@ -24,7 +26,7 @@ Add the missing functions to the resource. ### Wrong -``` PowerShell +```powershell function Get-TargetResource { [OutputType([Hashtable])] @@ -50,7 +52,7 @@ function Set-TargetResource ``` ### Correct -``` PowerShell +```powershell function Get-TargetResource { [OutputType([Hashtable])] @@ -91,7 +93,7 @@ function Test-TargetResource ### Wrong -``` PowerShell +```powershell [DscResource()] class MyDSCResource { @@ -111,7 +113,7 @@ class MyDSCResource ### Correct -``` PowerShell +```powershell [DscResource()] class MyDSCResource { diff --git a/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md b/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md index 053925f16..6a20dbcf2 100644 --- a/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md +++ b/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md @@ -4,11 +4,14 @@ ## Description -For script based DSC resources, if a property is declared with attributes `Key` of `Required` in a mof file, then is should be present as a mandatory parameter in the corresponding `Get-TargetResource`, `Set-TargetResource` and `Test-TargetResource` functions. +For script based DSC resources, if a property is declared with attributes `Key` of `Required` in a +mof file, then is should be present as a mandatory parameter in the corresponding +`Get-TargetResource`, `Set-TargetResource` and `Test-TargetResource` functions. ## How -Make sure all the properties with `Key` and `Required` attributes have equivalent mandatory parameters in the `Get/Set/Test` functions. +Make sure all the properties with `Key` and `Required` attributes have equivalent mandatory +parameters in the `Get/Set/Test` functions. ## Example @@ -27,7 +30,7 @@ class WaitForAny : OMI_BaseResource ### Wrong -``` PowerShell +```powershell function Get-TargetResource { [CmdletBinding()] @@ -77,7 +80,7 @@ function Test-TargetResource ### Correct -``` PowerShell +```powershell function Get-TargetResource { [CmdletBinding()] diff --git a/RuleDocumentation/DSCUseIdenticalParametersForDSC.md b/RuleDocumentation/DSCUseIdenticalParametersForDSC.md index 8d595db93..8c3d03a50 100644 --- a/RuleDocumentation/DSCUseIdenticalParametersForDSC.md +++ b/RuleDocumentation/DSCUseIdenticalParametersForDSC.md @@ -4,7 +4,8 @@ ## Description -The `Get-TargetResource`, `Test-TargetResource` and `Set-TargetResource` functions of DSC Resource must have the same parameters. +The `Get-TargetResource`, `Test-TargetResource` and `Set-TargetResource` functions of DSC Resource +must have the same parameters. ## How @@ -14,7 +15,7 @@ Correct the parameters for the functions in DSC resource. ### Wrong -``` PowerShell +```powershell function Get-TargetResource { [OutputType([Hashtable])] @@ -56,7 +57,7 @@ function Test-TargetResource ### Correct -``` PowerShell +```powershell function Get-TargetResource { [OutputType([Hashtable])] diff --git a/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md b/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md index d96a4c28a..019b2dbc9 100644 --- a/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md +++ b/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md @@ -4,7 +4,8 @@ ## Description -Best practice recommends that additional user information is provided within commands, functions and scripts using `Write-Verbose`. +Best practice recommends that additional user information is provided within commands, functions and +scripts using `Write-Verbose`. ## How @@ -14,7 +15,7 @@ Make use of the `Write-Verbose` command. ### Wrong -``` PowerShell +```powershell Function Test-Function { [CmdletBinding()] @@ -25,7 +26,7 @@ Function Test-Function ### Correct -``` PowerShell +```powershell Function Test-Function { [CmdletBinding()] diff --git a/RuleDocumentation/MisleadingBacktick.md b/RuleDocumentation/MisleadingBacktick.md index a5b581601..da36ef77c 100644 --- a/RuleDocumentation/MisleadingBacktick.md +++ b/RuleDocumentation/MisleadingBacktick.md @@ -4,4 +4,4 @@ ## Description -Checks that lines don't end with a backtick followed by whitespace. \ No newline at end of file +Checks that lines don't end with a backtick followed by whitespace. diff --git a/RuleDocumentation/MissingModuleManifestField.md b/RuleDocumentation/MissingModuleManifestField.md index e5eec77b8..82cfc41d9 100644 --- a/RuleDocumentation/MissingModuleManifestField.md +++ b/RuleDocumentation/MissingModuleManifestField.md @@ -4,11 +4,13 @@ ## Description -A module manifest is a `.psd1` file that contains a hash table. The keys and values in the hash table describe the contents and attributes of the module, define the -prerequisites, and determine how the components are processed. +A module manifest is a `.psd1` file that contains a hash table. The keys and values in the hash +table describe the contents and attributes of the module, define the prerequisites, and determine +how the components are processed. Module manifests must contain the following keys (and a corresponding value) to be considered valid: -* `ModuleVersion` + +- `ModuleVersion` All other keys are optional. The order of the entries is not important. @@ -20,7 +22,7 @@ Please consider adding the missing fields to the manifest. ### Wrong -``` PowerShell +```powershell @{ Author = 'PowerShell Author' NestedModules = @('.\mymodule.psm1') @@ -32,7 +34,7 @@ Please consider adding the missing fields to the manifest. ### Correct -``` PowerShell +```powershell @{ ModuleVersion = '1.0' Author = 'PowerShell Author' diff --git a/RuleDocumentation/PlaceCloseBrace.md b/RuleDocumentation/PlaceCloseBrace.md index e8feb4884..970933549 100644 --- a/RuleDocumentation/PlaceCloseBrace.md +++ b/RuleDocumentation/PlaceCloseBrace.md @@ -4,21 +4,22 @@ ## Description -Close brace placement should follow a consistent style. It should be on a new line by itself and should not be followed by an empty line. +Close brace placement should follow a consistent style. It should be on a new line by itself and +should not be followed by an empty line. **Note**: This rule is not enabled by default. The user needs to enable it through settings. ## Configuration ```powershell - Rules = @{ - PSPlaceCloseBrace = @{ - Enable = $true - NoEmptyLineBefore = $false - IgnoreOneLineBlock = $true - NewLineAfter = $true - } +Rules = @{ + PSPlaceCloseBrace = @{ + Enable = $true + NoEmptyLineBefore = $false + IgnoreOneLineBlock = $true + NewLineAfter = $true } +} ``` ### Parameters @@ -33,10 +34,11 @@ Create violation if there is an empty line before a close brace. #### IgnoreOneLineBlock: bool (Default value is `$true`) -Indicates if close braces in a one line block should be ignored or not. -E.g. $x = if ($true) { "blah" } else { "blah blah" } -In the above example, if the property is set to true then the rule will not fire a violation. +Indicates if closed brace pairs in a one line block should be ignored or not. For example, +`$x = if ($true) { "blah" } else { "blah blah" }`, if the property is set to true then the rule +doesn't fire a violation. #### NewLineAfter: bool (Default value is `$true`) -Indicates if a new line should follow a close brace. If set to true a close brace should be followed by a new line. +Indicates if a new line should follow a close brace. If set to true a close brace should be followed +by a new line. diff --git a/RuleDocumentation/PlaceOpenBrace.md b/RuleDocumentation/PlaceOpenBrace.md index 31949901c..e50d13ca9 100644 --- a/RuleDocumentation/PlaceOpenBrace.md +++ b/RuleDocumentation/PlaceOpenBrace.md @@ -4,21 +4,22 @@ ## Description -Open brace placement should follow a consistent style. It can either follow KR style (on same line) or the Allman style (not on same line). +Open brace placement should follow a consistent style. It can either follow K&R style (on same line) +or the Allman style (not on same line). **Note**: This rule is not enabled by default. The user needs to enable it through settings. ## Configuration ```powershell - Rules = @{ - PSPlaceOpenBrace = @{ - Enable = $true - OnSameLine = $true - NewLineAfter = $true - IgnoreOneLineBlock = $true - } +Rules = @{ + PSPlaceOpenBrace = @{ + Enable = $true + OnSameLine = $true + NewLineAfter = $true + IgnoreOneLineBlock = $true } +} ``` ### Parameters @@ -37,6 +38,6 @@ Enforce a new line character after an open brace. The default value is true. #### IgnoreOneLineBlock: bool (Default value is `$true`) -Indicates if open braces in a one line block should be ignored or not. -E.g. $x = if ($true) { "blah" } else { "blah blah" } -In the above example, if the property is set to true then the rule will not fire a violation. +Indicates if open braces in a one line block should be ignored or not. For example, +` $x = if ($true) { "blah" } else { "blah blah" }`, if the property is set to true then the rule +doesn't fire a violation. diff --git a/RuleDocumentation/PossibleIncorrectComparisonWithNull.md b/RuleDocumentation/PossibleIncorrectComparisonWithNull.md index bfcde4672..6bd5a0db2 100644 --- a/RuleDocumentation/PossibleIncorrectComparisonWithNull.md +++ b/RuleDocumentation/PossibleIncorrectComparisonWithNull.md @@ -4,11 +4,19 @@ ## Description -To ensure that PowerShell performs comparisons correctly, the `$null` element should be on the left side of the operator. +To ensure that PowerShell performs comparisons correctly, the `$null` element should be on the left +side of the operator. -There are a number of reasons why this should occur: -* `$null` is a scalar. When the input (left side) to an operator is a scalar value, comparison operators return a Boolean value. When the input is a collection of values, the comparison operators return any matching values, or an empty array if there are no matches in the collection. The only way to reliably check if a value is `$null` is to place `$null` on the left side of the operator so that a scalar comparison is performed. -* PowerShell will perform type casting left to right, resulting in incorrect comparisons when `$null` is cast to other scalar types. +There are multiple reasons why this occurs: + +- `$null` is a scalar value. When the value on the left side of an operator is a scalar, comparison + operators return a **Boolean** value. When the value is a collection, the comparison operators + return any matching values or an empty array if there are no matches in the collection. +- PowerShell performs type casting left to right, resulting in incorrect comparisons when `$null` is + cast to other scalar types. + +The only way to reliably check if a value is `$null` is to place `$null` on the left side of the +operator so that a scalar comparison is performed. ## How @@ -16,42 +24,50 @@ Move `$null` to the left side of the comparison. ## Example -### Wrong? +### Wrong -``` PowerShell +```powershell function Test-CompareWithNull { - if ($DebugPreference -eq $null) - { - } + if ($DebugPreference -eq $null) + { + } } ``` ### Correct -``` PowerShell +```powershell function Test-CompareWithNull { - if ($null -eq $DebugPreference) - { - } + if ($null -eq $DebugPreference) + { + } } ``` ## Try it Yourself -``` PowerShell -# Both expressions below return 'false' because the comparison does not return an object and therefore the if statement always falls through: +```powershell +# Both expressions below return 'false' because the comparison does not return an +# object and therefore the if statement always falls through: if (@() -eq $null) { 'true' } else { 'false' } -if (@() -ne $null) { 'true' }else { 'false' } +if (@() -ne $null) { 'true' } else { 'false' } ``` -This is just the way how the comparison operator works (by design) but as demonstrated this can lead to unintuitive behaviour, especially when the intent is just a null check. The following example demonstrated the designed behaviour of the comparison operator, whereby for each element in the collection, the comparison with the right hand side is done, and where true, that element in the collection is returned. -``` PowerShell + +This is how the comparison operator works by-design. But, as demonstrated, this can lead +to non-intuitive behavior, especially when the intent is simple test for null. + +The following example demonstrates the designed behavior of the comparison operator when the +left-hand side is a collection. Each element in the collection is compared the right-hand side +value. When true, that element of the collection is returned. + +```powershell PS> 1,2,3,1,2 -eq $null -PS> 1,2,3,1,2 -eq 1 +PS> 1,2,3,1,2 -eq 1 1 1 -PS> (1,2,3,1,2 -eq $null).count +PS> (1,2,3,1,2 -eq $null).count 0 PS> (1,2,$null,3,$null,1,2 -eq $null).count 2 diff --git a/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md b/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md index 5089c103a..40b2d9159 100644 --- a/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md +++ b/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md @@ -4,51 +4,58 @@ ## Description -In many programming languages, the equality operator is denoted as `==` or `=` in many programming languages, but `PowerShell` uses `-eq`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high. +In many programming languages, the equality operator is denoted as `==` or `=`, but `PowerShell` uses `-eq`. Therefore, it can easily happen that the wrong operator is +used unintentionally. This rule catches a few special cases where the likelihood of that is quite +high. -The rule looks for usages of `==` and `=` operators inside `if`, `else if`, `while` and `do-while` statements but it will not warn if any kind of command or expression is used at the right hand side as this is probably by design. +The rule looks for usages of `==` and `=` operators inside `if`, `else if`, `while` and `do-while` +statements but it does not warn if any kind of command or expression is used at the right hand side +as this is probably by design. ## Example ### Wrong -```` PowerShell +```powershell if ($a = $b) { ... } -```` +``` -```` PowerShell +```powershell if ($a == $b) { } -```` +``` ### Correct -```` PowerShell +```powershell if ($a -eq $b) # Compare $a with $b { ... } -```` +``` -```` PowerShell +```powershell if ($a = Get-Something) # Only execute action if command returns something and assign result to variable { Do-SomethingWith $a } -```` +``` ## Implicit suppresion using Clang style -There are some rare cases where assignment of variable inside an if statement is by design. Instead of suppression the rule, one can also signal that assignment was intentional by wrapping the expression in extra parenthesis. An exception for this is when `$null` is used on the LHS is used because there is no use case for this. +There are some rare cases where assignment of variable inside an `if` statement is by design. +Instead of suppressing the rule, one can also signal that assignment was intentional by wrapping the +expression in extra parenthesis. An exception for this is when `$null` is used on the LHS because +there is no use case for this. -```` powershell +```powershell if (($shortVariableName = $SuperLongVariableName['SpecialItem']['AnotherItem'])) { ... } -```` \ No newline at end of file +``` diff --git a/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md b/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md index 6af16c0a7..0a3cdb87a 100644 --- a/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md +++ b/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md @@ -4,26 +4,30 @@ ## Description -In many programming languages, the comparison operator for 'greater than' is `>` but `PowerShell` uses `-gt` for it and `-ge` (greater or equal) for `>=`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high. +In many programming languages, the comparison operator for 'greater than' is `>` but `PowerShell` +uses `-gt` for it and `-ge` (greater or equal) for `>=`. Therefore, it can easily happen that the +wrong operator is used unintentionally. This rule catches a few special cases where the likelihood +of that is quite high. -The rule looks for usages of `>` or `>=` operators inside if, elseif, while and do-while statements because this is likely going to be unintentional usage. +The rule looks for usages of `>` or `>=` operators inside `if`, `elseif`, `while` and `do-while` +statements because this is likely going to be unintentional usage. ## Example ### Wrong -```` PowerShell +```powershell if ($a > $b) { ... } -```` +``` ### Correct -```` PowerShell +```powershell if ($a -gt $b) { ... } -```` \ No newline at end of file +``` diff --git a/RuleDocumentation/ProvideCommentHelp.md b/RuleDocumentation/ProvideCommentHelp.md index bfd922c63..c250bc2b4 100644 --- a/RuleDocumentation/ProvideCommentHelp.md +++ b/RuleDocumentation/ProvideCommentHelp.md @@ -4,9 +4,15 @@ ## Description -Comment based help should be provided for all PowerShell commands. This test only checks for the presence of comment based help and not on the validity or format. +Comment based help should be provided for all PowerShell commands. This test only checks for the +presence of comment based help and not on the validity or format. -For assistance on comment based help, use the command ```Get-Help about_comment_based_help``` or the article, "How to Write Cmdlet Help" (https://go.microsoft.com/fwlink/?LinkID=123415). +For assistance on comment based help, use the command `Get-Help about_comment_based_help` or the +following articles: + +- [Writing Comment-based Help](https://docs.microsoft.com/powershell/scripting/developer/help/writing-comment-based-help-topics) +- [Writing Help for PowerShell Cmdlets](https://docs.microsoft.com/powershell/scripting/developer/help/writing-help-for-windows-powershell-cmdlets) +- [Create XML-based help using PlatyPS](https://docs.microsoft.com/powershell/scripting/dev-cross-plat/create-help-using-platyps) ## Configuration @@ -30,12 +36,13 @@ Enable or disable the rule during ScriptAnalyzer invocation. #### ExportedOnly: bool (Default value is `$true`) -If enabled, throw violation only on functions/cmdlets that are exported using the 'Export-ModuleMember' cmdlet. +If enabled, throw violation only on functions/cmdlets that are exported using the +`Export-ModuleMember` cmdlet. #### BlockComment: bool (Default value is `$true`) -If enabled, returns comment help in block comment style, i.e., `<#...#>`. Otherwise returns -comment help in line comment style, i.e., each comment line starts with `#`. +If enabled, returns comment help in block comment style, i.e., `<#...#>`. Otherwise returns comment +help in line comment style, i.e., each comment line starts with `#`. #### VSCodeSnippetCorrection: bool (Default value is `$false`) @@ -45,18 +52,18 @@ If enabled, returns comment help in vscode snippet format. Represents the position of comment help with respect to the function definition. -Possible values are: `before`, `begin` and `end`. If any invalid value is given, the -property defaults to `before`. +Possible values are: `before`, `begin` and `end`. If any invalid value is given, the property +defaults to `before`. -`before` means the help is placed before the function definition. -`begin` means the help is placed at the begining of the function definition body. -`end` means the help is places the end of the function definition body. +`before` means the help is placed before the function definition. `begin` means the help is placed +at the beginning of the function definition body. `end` means the help is places the end of the +function definition body. ## Example ### Wrong -``` PowerShell +```powershell function Get-File { [CmdletBinding()] @@ -70,7 +77,7 @@ function Get-File ### Correct -``` PowerShell +```powershell <# .Synopsis Short description diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md index 25338085a..5eabee967 100644 --- a/RuleDocumentation/README.md +++ b/RuleDocumentation/README.md @@ -2,73 +2,76 @@ ## Table of Contents -| Rule | Severity | Configurable | -|------|----------------------------------|--------------| -|[AlignAssignmentStatement](./AlignAssignmentStatement.md) | Warning | | -|[AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md) | Warning | | -|[AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | | -|[AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | | -|[AvoidGlobalAliases*](./AvoidGlobalAliases.md) | Warning | | -|[AvoidGlobalFunctions](./AvoidGlobalFunctions.md) | Warning | | -|[AvoidGlobalVars](./AvoidGlobalVars.md) | Warning | | -|[AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning | | -|[AvoidLongLines](./AvoidLongLines.md) | Warning | | -|[AvoidMultipleTypeAttributes](./AvoidMultipleTypeAttributes.md) | Warning | | -|[AvoidOverwritingBuiltInCmdlets](./AvoidOverwritingBuiltInCmdlets.md) | Warning | | -|[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | | -|[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | | -|[UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md) | Warning | | -|[AvoidUsingDoubleQuotesForConstantString](./AvoidUsingDoubleQuotesForConstantString.md) | Warning | Yes | -|[AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes | -|[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | | -|[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | | -|[AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning | | -|[AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md) | Warning | | -|[AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning | | -|[AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning | | -|[AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning | | -|[AvoidTrailingWhitespace](./AvoidTrailingWhitespace.md) | Warning | | -|[AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | | -|[AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning | | -|[AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning | | -|[DSCDscExamplesPresent](./DSCDscExamplesPresent.md) | Information | | -|[DSCDscTestsPresent](./DSCDscTestsPresent.md) | Information | | -|[DSCReturnCorrectTypesForDSCFunctions](./DSCReturnCorrectTypesForDSCFunctions.md) | Information | | -|[DSCStandardDSCFunctionsInResource](./DSCStandardDSCFunctionsInResource.md) | Error | | -|[DSCUseIdenticalMandatoryParametersForDSC](./DSCUseIdenticalMandatoryParametersForDSC.md) | Error | | -|[DSCUseIdenticalParametersForDSC](./DSCUseIdenticalParametersForDSC.md) | Error | | -|[DSCUseVerboseMessageInDSCResource](./DSCUseVerboseMessageInDSCResource.md) | Error | | -|[MisleadingBacktick](./MisleadingBacktick.md) | Warning | | -|[MissingModuleManifestField](./MissingModuleManifestField.md) | Warning | | -|[PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md) | Warning | | -|[PossibleIncorrectUsageOfAssignmentOperator](./PossibleIncorrectUsageOfAssignmentOperator.md) | Warning | | -|[PossibleIncorrectUsageOfRedirectionOperator](./PossibleIncorrectUsageOfRedirectionOperator.md) | Warning | | -|[ProvideCommentHelp](./ProvideCommentHelp.md) | Information | Yes | -|[ReservedCmdletChar](./ReservedCmdletChar.md) | Error | | -|[ReservedParams](./ReservedParams.md) | Error | | -|[ReviewUnusedParameter](./ReviewUnusedParameter.md) | Warning | | -|[ShouldProcess](./ShouldProcess.md) | Error | | -|[UseApprovedVerbs](./UseApprovedVerbs.md) | Warning | | -|[UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning | | -|[UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning | | -|[UseCorrectCasing](./UseCorrectCasing.md) | Information | | -|[UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning | | -|[UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | | -|[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | | -|[UseProcessBlockForPipelineCommand](./UseProcessBlockForPipelineCommand.md) | Warning | | -|[UsePSCredentialType](./UsePSCredentialType.md) | Warning | | -|[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | | -|[UseSingularNouns](./UseSingularNouns.md) | Warning | | -|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | | -|[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | | -|[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning | Yes | -|[UseCompatibleCommands](./UseCompatibleCommands.md) | Warning | Yes | -|[UseCompatibleSyntax](./UseCompatibleSyntax.md) | Warning | Yes | -|[UseCompatibleTypes](./UseCompatibleTypes.md) | Warning | Yes | -|[PlaceOpenBrace](./PlaceOpenBrace.md) | Warning | Yes | -|[PlaceCloseBrace](./PlaceCloseBrace.md) | Warning | Yes | -|[UseConsistentIndentation](./UseConsistentIndentation.md) | Warning | Yes | -|[UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning | Yes | -|[UseUTF8EncodingForHelpFile](./UseUTF8EncodingForHelpFile.md) | Warning | | +| Rule | Severity | Enabled by default | Configurable | +| ------------------------------------------------------------------------------------------------- | ----------- | :----------------: | :-------------: | +| [AlignAssignmentStatement](./AlignAssignmentStatement.md) | Warning | No | Yes | +| [AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md) | Warning | Yes | | +| [AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | Yes | | +| [AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | Yes | | +| [AvoidGlobalAliases1](./AvoidGlobalAliases.md) | Warning | Yes | | +| [AvoidGlobalFunctions](./AvoidGlobalFunctions.md) | Warning | Yes | | +| [AvoidGlobalVars](./AvoidGlobalVars.md) | Warning | Yes | | +| [AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning | Yes | | +| [AvoidLongLines](./AvoidLongLines.md) | Warning | No | Yes | +| [AvoidMultipleTypeAttributes1](./AvoidMultipleTypeAttributes.md) | Warning | Yes | | +| [AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | Yes | | +| [AvoidOverwritingBuiltInCmdlets](./AvoidOverwritingBuiltInCmdlets.md) | Warning | Yes | Yes | +| [AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | Yes | | +| [AvoidTrailingWhitespace](./AvoidTrailingWhitespace.md) | Warning | Yes | | +| [AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes | Yes2 | +| [AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | Yes | | +| [AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | Yes | | +| [AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning | Yes | | +| [AvoidUsingDoubleQuotesForConstantString](./AvoidUsingDoubleQuotesForConstantString.md) | Warning | No | Yes | +| [AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md) | Warning | Yes | | +| [AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning | Yes | | +| [AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning | Yes | | +| [AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning | Yes | | +| [AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | Yes | | +| [AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning | Yes | | +| [AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning | Yes | | +| [DSCDscExamplesPresent](./DSCDscExamplesPresent.md) | Information | Yes | | +| [DSCDscTestsPresent](./DSCDscTestsPresent.md) | Information | Yes | | +| [DSCReturnCorrectTypesForDSCFunctions](./DSCReturnCorrectTypesForDSCFunctions.md) | Information | Yes | | +| [DSCStandardDSCFunctionsInResource](./DSCStandardDSCFunctionsInResource.md) | Error | Yes | | +| [DSCUseIdenticalMandatoryParametersForDSC](./DSCUseIdenticalMandatoryParametersForDSC.md) | Error | Yes | | +| [DSCUseIdenticalParametersForDSC](./DSCUseIdenticalParametersForDSC.md) | Error | Yes | | +| [DSCUseVerboseMessageInDSCResource](./DSCUseVerboseMessageInDSCResource.md) | Error | Yes | | +| [MisleadingBacktick](./MisleadingBacktick.md) | Warning | Yes | | +| [MissingModuleManifestField](./MissingModuleManifestField.md) | Warning | Yes | | +| [PlaceCloseBrace](./PlaceCloseBrace.md) | Warning | No | Yes | +| [PlaceOpenBrace](./PlaceOpenBrace.md) | Warning | No | Yes | +| [PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md) | Warning | Yes | | +| [PossibleIncorrectUsageOfAssignmentOperator](./PossibleIncorrectUsageOfAssignmentOperator.md) | Warning | Yes | | +| [PossibleIncorrectUsageOfRedirectionOperator](./PossibleIncorrectUsageOfRedirectionOperator.md) | Warning | Yes | | +| [ProvideCommentHelp](./ProvideCommentHelp.md) | Information | Yes | Yes | +| [ReservedCmdletChar](./ReservedCmdletChar.md) | Error | Yes | | +| [ReservedParams](./ReservedParams.md) | Error | Yes | | +| [ReviewUnusedParameter](./ReviewUnusedParameter.md) | Warning | Yes | | +| [ShouldProcess](./ShouldProcess.md) | Error | Yes | | +| [UseApprovedVerbs](./UseApprovedVerbs.md) | Warning | Yes | | +| [UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning | Yes | | +| [UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning | Yes | | +| [UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning | Yes | Yes2 | +| [UseCompatibleCommands](./UseCompatibleCommands.md) | Warning | No | Yes | +| [UseCompatibleSyntax](./UseCompatibleSyntax.md) | Warning | No | Yes | +| [UseCompatibleTypes](./UseCompatibleTypes.md) | Warning | No | Yes | +| [UseConsistentIndentation](./UseConsistentIndentation.md) | Warning | No | Yes | +| [UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning | No | Yes | +| [UseCorrectCasing](./UseCorrectCasing.md) | Information | No | Yes | +| [UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning | Yes | | +| [UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | Yes | | +| [UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | Yes | | +| [UseProcessBlockForPipelineCommand](./UseProcessBlockForPipelineCommand.md) | Warning | Yes | | +| [UsePSCredentialType](./UsePSCredentialType.md) | Warning | Yes | | +| [UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | Yes | | +| [UseSingularNouns1](./UseSingularNouns.md) | Warning | Yes | | +| [UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | Yes | | +| [UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | Yes | | +| [UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md) | Warning | Yes | | +| [UseUTF8EncodingForHelpFile](./UseUTF8EncodingForHelpFile.md) | Warning | Yes | | -* Rule is not available on all PowerShell versions, editions and/or OS platforms. See the rule's documentation for details. +- 1 Rule is not available on all PowerShell versions, editions, or OS platforms. See the + rule's documentation for details. +- 2 The rule a configurable property, but the rule can't be disabled like other + configurable rules. diff --git a/RuleDocumentation/ReservedCmdletChar.md b/RuleDocumentation/ReservedCmdletChar.md index 5443ae010..c6b026bd4 100644 --- a/RuleDocumentation/ReservedCmdletChar.md +++ b/RuleDocumentation/ReservedCmdletChar.md @@ -4,9 +4,10 @@ ## Description -You cannot use following reserved characters in a function or cmdlet name as these can cause parsing or runtime errors. +You cannot use following reserved characters in a function or cmdlet name as these can cause parsing +or runtime errors. -Reserved Characters include: `#,(){}[]&/\\$^;:\"'<>|?@`*%+=~` +Reserved Characters include: ``#,(){}[]&/\\$^;:\"'<>|?@`*%+=~`` ## How @@ -16,14 +17,14 @@ Remove reserved characters from names. ### Wrong -``` PowerShell +```powershell function MyFunction[1] {...} ``` ### Correct -``` PowerShell +```powershell function MyFunction {...} ``` diff --git a/RuleDocumentation/ReservedParams.md b/RuleDocumentation/ReservedParams.md index b00f77691..923be9a87 100644 --- a/RuleDocumentation/ReservedParams.md +++ b/RuleDocumentation/ReservedParams.md @@ -14,7 +14,7 @@ Change the name of the parameter. ### Wrong -``` PowerShell +```powershell function Test { [CmdletBinding] @@ -28,7 +28,7 @@ function Test ### Correct -``` PowerShell +```powershell function Test { [CmdletBinding] diff --git a/RuleDocumentation/ReviewUnusedParameter.md b/RuleDocumentation/ReviewUnusedParameter.md index 82af88c62..72095552c 100644 --- a/RuleDocumentation/ReviewUnusedParameter.md +++ b/RuleDocumentation/ReviewUnusedParameter.md @@ -1,45 +1,46 @@ -# ReviewUnusedParameter - -**Severity Level: Warning** - -## Description - -This rule identifies parameters declared in a script, scriptblock, or function scope that have not been used in that scope. - -## How - -Consider removing the unused parameter. - -## Example - -### Wrong - -``` PowerShell -function Test-Parameter -{ - Param ( - $Parameter1, - - # this parameter is never called in the function - $Parameter2 - ) - - Get-Something $Parameter1 -} -``` - -### Correct - -``` PowerShell -function Test-Parameter -{ - Param ( - $Parameter1, - - # now this parameter is being called in the same scope - $Parameter2 - ) - - Get-Something $Parameter1 $Parameter2 -} -``` +# ReviewUnusedParameter + +**Severity Level: Warning** + +## Description + +This rule identifies parameters declared in a script, scriptblock, or function scope that have not +been used in that scope. + +## How + +Consider removing the unused parameter. + +## Example + +### Wrong + +```powershell +function Test-Parameter +{ + Param ( + $Parameter1, + + # this parameter is never called in the function + $Parameter2 + ) + + Get-Something $Parameter1 +} +``` + +### Correct + +```powershell +function Test-Parameter +{ + Param ( + $Parameter1, + + # now this parameter is being called in the same scope + $Parameter2 + ) + + Get-Something $Parameter1 $Parameter2 +} +``` diff --git a/RuleDocumentation/ShouldProcess.md b/RuleDocumentation/ShouldProcess.md index aa5c74214..053627f1f 100644 --- a/RuleDocumentation/ShouldProcess.md +++ b/RuleDocumentation/ShouldProcess.md @@ -4,52 +4,58 @@ ## Description -If a cmdlet declares the `SupportsShouldProcess` attribute, then it should also call `ShouldProcess`. A violation is any function which either declares `SupportsShouldProcess` attribute but makes no calls to `ShouldProcess` or it calls `ShouldProcess` but does not declare `SupportsShouldProcess` +If a cmdlet declares the `SupportsShouldProcess` attribute, then it should also call +`ShouldProcess`. A violation is any function which either declares `SupportsShouldProcess` attribute +but makes no calls to `ShouldProcess` or it calls `ShouldProcess` but does not declare +`SupportsShouldProcess` -For more information, please refer to `about_Functions_Advanced_Methods` and `about_Functions_CmdletBindingAttribute` +For more information, please refer to `about_Functions_Advanced_Methods` and +`about_Functions_CmdletBindingAttribute` ## How -To fix a violation of this rule, please call `ShouldProcess` method when a cmdlet declares `SupportsShouldProcess` attribute. Or please add `SupportsShouldProcess` attribute argument when calling `ShouldProcess` +To fix a violation of this rule, please call `ShouldProcess` method when a cmdlet declares +`SupportsShouldProcess` attribute. Or please add `SupportsShouldProcess` attribute argument when +calling `ShouldProcess` ## Example ### Wrong -``` PowerShell - function Set-File - { - [CmdletBinding(SupportsShouldProcess=$true)] - Param - ( - # Path to file - [Parameter(Mandatory=$true)] - $Path - ) - "String" | Out-File -FilePath $FilePath - } +```powershell + function Set-File + { + [CmdletBinding(SupportsShouldProcess=$true)] + Param + ( + # Path to file + [Parameter(Mandatory=$true)] + $Path + ) + "String" | Out-File -FilePath $FilePath + } ``` ### Correct -``` PowerShell - function Set-File - { - [CmdletBinding(SupportsShouldProcess=$true)] - Param - ( - # Path to file - [Parameter(Mandatory=$true)] - $Path - ) - - if ($PSCmdlet.ShouldProcess("Target", "Operation")) - { - "String" | Out-File -FilePath $FilePath - } - else - { - Write-Host ('Write "String" to file {0}' -f $FilePath) - } - } +```powershell + function Set-File + { + [CmdletBinding(SupportsShouldProcess=$true)] + Param + ( + # Path to file + [Parameter(Mandatory=$true)] + $Path + ) + + if ($PSCmdlet.ShouldProcess("Target", "Operation")) + { + "String" | Out-File -FilePath $FilePath + } + else + { + Write-Host ('Write "String" to file {0}' -f $FilePath) + } + } ``` diff --git a/RuleDocumentation/UseApprovedVerbs.md b/RuleDocumentation/UseApprovedVerbs.md index abd159c9d..5627e9452 100644 --- a/RuleDocumentation/UseApprovedVerbs.md +++ b/RuleDocumentation/UseApprovedVerbs.md @@ -4,15 +4,15 @@ ## Description -All CMDLets must used approved verbs. +All cmdlets must used approved verbs. Approved verbs can be found by running the command `Get-Verb`. Additional documentation on approved verbs can be found in the microsoft docs page [Approved Verbs for PowerShell Commands](https://docs.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands). -Some unapproved verbs are documented on the approved verbs page and point to approved alternatives; -try searching for the verb you used to find its approved form. -For example, searching for `Read`, `Open`, or `Search` will lead you to `Get`. +Some unapproved verbs are documented on the approved verbs page and point to approved alternatives. +Try searching for the verb you used to find its approved form. For example, searching for `Read`, +`Open`, or `Search` leads you to `Get`. ## How @@ -22,16 +22,16 @@ Change the verb in the cmdlet's name to an approved verb. ### Wrong -``` PowerShell +```powershell function Change-Item { ... } -```` +``` ### Correct -``` PowerShell +```powershell function Update-Item { ... diff --git a/RuleDocumentation/UseBOMForUnicodeEncodedFile.md b/RuleDocumentation/UseBOMForUnicodeEncodedFile.md index d8353eaa2..cc287eadc 100644 --- a/RuleDocumentation/UseBOMForUnicodeEncodedFile.md +++ b/RuleDocumentation/UseBOMForUnicodeEncodedFile.md @@ -4,7 +4,8 @@ ## Description -For a file encoded with a format other than ASCII, ensure Byte Order Mark (BOM) is present to ensure that any application consuming this file can interpret it correctly. +For a file encoded with a format other than ASCII, ensure Byte Order Mark (BOM) is present to ensure +that any application consuming this file can interpret it correctly. ## How diff --git a/RuleDocumentation/UseCmdletCorrectly.md b/RuleDocumentation/UseCmdletCorrectly.md index 9405a6381..e7558d37c 100644 --- a/RuleDocumentation/UseCmdletCorrectly.md +++ b/RuleDocumentation/UseCmdletCorrectly.md @@ -4,7 +4,8 @@ ## Description -Whenever we call a command, care should be taken that it is invoked with the correct syntax and parameters. +Whenever we call a command, care should be taken that it is invoked with the correct syntax and +parameters. ## How @@ -14,21 +15,21 @@ Specify all mandatory parameters when calling commands. ### Wrong -``` PowerShell +```powershell Function Set-TodaysDate () { - Set-Date - ... + Set-Date + ... } ``` ### Correct -``` PowerShell +```powershell Function Set-TodaysDate () { - $date = Get-Date - Set-Date -Date $date - ... + $date = Get-Date + Set-Date -Date $date + ... } ``` diff --git a/RuleDocumentation/UseCompatibleCmdlets.md b/RuleDocumentation/UseCompatibleCmdlets.md index 75cae8e67..a2ae7fe43 100644 --- a/RuleDocumentation/UseCompatibleCmdlets.md +++ b/RuleDocumentation/UseCompatibleCmdlets.md @@ -4,9 +4,15 @@ ## Description -This rule flags cmdlets that are not available in a given Edition/Version of PowerShell on a given Operating System. It works by comparing a cmdlet against a set of allowlists which ship with PSScriptAnalyzer. They can be found at `/path/to/PSScriptAnalyzerModule/Settings`. These files are of the form, `PSEDITION-PSVERSION-OS.json` where `PSEDITION` can be either `Core` or `Desktop`, `OS` can be either `Windows`, `Linux` or `MacOS`, and `Version` is the PowerShell version. To enable the rule to check if your script is compatible on PowerShell Core on windows, put the following your settings file: +This rule flags cmdlets that are not available in a given Edition/Version of PowerShell on a given +Operating System. It works by comparing a cmdlet against a set of allowlists which ship with +PSScriptAnalyzer. They can be found at `/path/to/PSScriptAnalyzerModule/Settings`. These files are +of the form, `--.json` where `` can be either `Core` or +`Desktop`, `` can be either `Windows`, `Linux` or `MacOS`, and `` is the PowerShell +version. To enable the rule to check if your script is compatible on PowerShell Core on windows, put +the following your settings file: -```PowerShell +```powershell @{ 'Rules' = @{ 'PSUseCompatibleCmdlets' = @{ @@ -27,5 +33,9 @@ The parameter `compatibility` is a list that contain any of the following - core-6.1.0-linux-arm (taken from Raspbian) - core-6.1.0-macos -Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major and minor versions of PowerShell are supplied. One can also create a custom settings file as well with the [New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) script and use it by placing the created `JSON` into the `Settings` folder of the `PSScriptAnalyzer` module installation folder, then the `compatibility` parameter is just its file name (that can also be changed if desired). -Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached it's end of life. \ No newline at end of file +Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major +and minor versions of PowerShell are supplied. You can also create a custom settings file with the +[New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) +script. Place the created `.json` file in the `Settings` folder of the `PSScriptAnalyzer` module +folder. Then the `compatibility` parameter values is just the filename. Note that the `core-6.0.2-*` +files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached it's end of life. diff --git a/RuleDocumentation/UseCompatibleCommands.md b/RuleDocumentation/UseCompatibleCommands.md index 86cf8b84e..0da44c8b0 100644 --- a/RuleDocumentation/UseCompatibleCommands.md +++ b/RuleDocumentation/UseCompatibleCommands.md @@ -18,24 +18,30 @@ Where: On Windows, this includes the SKU number. On Linux, this is the name of the distribution. - ``: The machine architecture the operating system is running on (this is usually `x64`). -- ``: The self-reported version of the operating system (on Linux, this is the distribution version). +- ``: The self-reported version of the operating system (on Linux, this is the + distribution version). - ``: The PowerShell version (from `$PSVersionTable.PSVersion`). - ``: The machine architecture of the PowerShell process. -- ``: The reported version of the .NET runtime PowerShell is running on (from `System.Environment.Version`). -- ``: The .NET runtime flavor PowerShell is running on (currently `framework` or `core`). +- ``: The reported version of the .NET runtime PowerShell is running on (from + `System.Environment.Version`). +- ``: The .NET runtime flavor PowerShell is running on (currently `framework` or + `core`). For example: -- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on Windows 10 Enterprise (build 18312) for x64. -- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same operating system. +- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on + Windows 10 Enterprise (build 18312) for x64. +- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same + operating system. - `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04. -Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in your configuration. +Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in +your configuration. Platforms bundled by default are: -| PowerShell Version | Operating System | ID | -| -------------------|---------------------- | --------------------------------------------------------------------- | +| PowerShell Version | Operating System | ID | +| ------------------ | --------------------- | --------------------------------------------------------------------- | | 3.0 | Windows Server 2012 | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework` | | 4.0 | Windows Server 2012R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework` | | 5.1 | Windows Server 2016 | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` | @@ -50,39 +56,43 @@ Platforms bundled by default are: | 7.0 | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_3.1.2_core` | | 7.0 | Ubuntu 18.04 LTS | `ubuntu_x64_18.04_6.2.4_x64_3.1.2_core` | -Other profiles can be found [here](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles). +Other profiles can be found in the +[GitHub repo](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles). -You can also generate your own platform profile using the [PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector). +You can also generate your own platform profile using the +[PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector). -The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. -A platform can be specified as: +The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. A +platform can be specified as: -- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` added to the end - and is searched for in the default profile directory. -- A file name (like `my_custom_platform.json`), which will be searched for the in the default profile directory. +- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` + added to the end and is searched for in the default profile directory. +- A filename (like `my_custom_platform.json`), which will be searched for the in the default + profile directory. - An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`). -The default profile directory is under the PSScriptAnalzyer module at `$PSScriptRoot/compatibility_profiles` -(where `$PSScriptRoot` here refers to the directory containing `PSScriptAnalyzer.psd1`). +The default profile directory is under the PSScriptAnalzyer module at +`$PSScriptRoot/compatibility_profiles` (where `$PSScriptRoot` here refers to the directory +containing `PSScriptAnalyzer.psd1`). -The compatibility analysis compares a command used to both a target profile -and a "union" profile (containing all commands available in *any* profile in the profile dir). -If a command is not present in the union profile, it is assumed to be locally created and ignored. -Otherwise, if a command is present in the union profile but not present in a target, -it is deemed to be incompatible with that target. +The compatibility analysis compares a command used to both a target profile and a "union" profile +(containing all commands available in *any* profile in the profile dir). If a command is not present +in the union profile, it is assumed to be locally created and ignored. Otherwise, if a command is +present in the union profile but not present in a target, it is deemed to be incompatible with that +target. ## Configuration settings -| Configuration key | Meaning | Accepted values | Mandatory | Example | -| ----------------- | ------- | --------------- | --------- | ------- | -| `Enable` | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` | -| `TargetProfiles` | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` | -| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` | -| `IgnoreCommands` | Commands to ignore compatibility of in scripts | string[]: names of commands to ignore | No (default: `@()`) | `@('Get-ChildItem','Import-Module')` | +| Configuration key | Meaning | Accepted values | Mandatory | Example | +| ----------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `Enable` | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` | +| `TargetProfiles` | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` | +| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` | +| `IgnoreCommands` | Commands to ignore compatibility of in scripts | string[]: names of commands to ignore | No (default: `@()`) | `@('Get-ChildItem','Import-Module')` | An example configuration might look like: -```PowerShell +```powershell @{ Rules = @{ PSUseCompatibleCommmands = @{ @@ -105,8 +115,8 @@ An example configuration might look like: ## Suppression -Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a scriptblock -as with other rules. +Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a +scriptblock as with other rules. ```powershell [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "")] diff --git a/RuleDocumentation/UseCompatibleSyntax.md b/RuleDocumentation/UseCompatibleSyntax.md index 4c51e9b97..c299dfb36 100644 --- a/RuleDocumentation/UseCompatibleSyntax.md +++ b/RuleDocumentation/UseCompatibleSyntax.md @@ -1,25 +1,24 @@ -# UseCompatibleSyntax - -**Severity Level: Warning** - -## Description - -This rule identifies syntax elements that are incompatible with targeted PowerShell versions. - -It cannot identify syntax elements incompatible with PowerShell 3/4 from PowerShell 3/4 -due to those PowerShell versions not being able to parse the incompatible syntaxes. - -```PowerShell -@{ - Rules = @{ - PSUseCompatibleSyntax = @{ - Enable = $true - TargetVersions = @( - "6.0", - "5.1", - "4.0" - ) - } - } -} -``` +# UseCompatibleSyntax + +**Severity Level: Warning** + +## Description + +This rule identifies syntax elements that are incompatible with targeted PowerShell versions. + +It cannot identify syntax elements incompatible with PowerShell 3 or 4 when run from those PowerShell versions because they aren't able to parse the incompatible syntaxes. + +```powershell +@{ + Rules = @{ + PSUseCompatibleSyntax = @{ + Enable = $true + TargetVersions = @( + "6.0", + "5.1", + "4.0" + ) + } + } +} +``` diff --git a/RuleDocumentation/UseCompatibleTypes.md b/RuleDocumentation/UseCompatibleTypes.md index c1a05f47d..f1574697a 100644 --- a/RuleDocumentation/UseCompatibleTypes.md +++ b/RuleDocumentation/UseCompatibleTypes.md @@ -4,7 +4,8 @@ ## Description -This rule identifies types that are not available (loaded by default) in targeted PowerShell platforms. +This rule identifies types that are not available (loaded by default) in targeted PowerShell +platforms. A PowerShell platform is identified by a name in the following format: @@ -18,24 +19,30 @@ Where: On Windows, this includes the SKU number. On Linux, this is the name of the distribution. - ``: The machine architecture the operating system is running on (this is usually `x64`). -- ``: The self-reported version of the operating system (on Linux, this is the distribution version). +- ``: The self-reported version of the operating system (on Linux, this is the + distribution version). - ``: The PowerShell version (from `$PSVersionTable.PSVersion`). - ``: The machine architecture of the PowerShell process. -- ``: The reported version of the .NET runtime PowerShell is running on (from `System.Environment.Version`). -- ``: The .NET runtime flavor PowerShell is running on (currently `framework` or `core`). +- ``: The reported version of the .NET runtime PowerShell is running on (from + `System.Environment.Version`). +- ``: The .NET runtime flavor PowerShell is running on (currently `framework` or + `core`). For example: -- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on Windows 10 Enterprise (build 18312) for x64. -- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same operating system. +- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on + Windows 10 Enterprise (build 18312) for x64. +- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same + operating system. - `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04. -Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in your configuration. +Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in +your configuration. Platforms bundled by default are: -| PowerShell Version | Operating System | ID | -| -------------------|---------------------- | --------------------------------------------------------------------- | +| PowerShell Version | Operating System | ID | +| ------------------ | --------------------- | --------------------------------------------------------------------- | | 3.0 | Windows Server 2012 | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework` | | 4.0 | Windows Server 2012R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework` | | 5.1 | Windows Server 2016 | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` | @@ -50,39 +57,42 @@ Platforms bundled by default are: | 7.0 | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_3.1.2_core` | | 7.0 | Ubuntu 18.04 LTS | `ubuntu_x64_18.04_6.2.4_x64_3.1.2_core` | -Other profiles can be found [here](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles). +Other profiles can be found in the +[GitHub repo](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles). -You can also generate your own platform profile using the [PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector). +You can also generate your own platform profile using the +[PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector). -The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. -A platform can be specified as: +The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. A +platform can be specified as: -- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` added to the end - and is searched for in the default profile directory. -- A file name (like `my_custom_platform.json`), which will be searched for the in the default profile directory. +- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` + added to the end and is searched for in the default profile directory. +- A filename (like `my_custom_platform.json`), which will be searched for the in the default profile + directory. - An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`). -The default profile directory is under the PSScriptAnalzyer module at `$PSScriptRoot/PSCompatibilityCollector/profiles` -(where `$PSScriptRoot` here refers to the directory containing `PSScriptAnalyzer.psd1`). +The default profile directory is under the PSScriptAnalzyer module at +`$PSScriptRoot/PSCompatibilityCollector/profiles` (where `$PSScriptRoot` here refers to the +directory containing `PSScriptAnalyzer.psd1`). -The compatibility analysis compares a type used to both a target profile -and a "union" profile (containing all types available in *any* profile in the profile dir). -If a type is not present in the union profile, it is assumed to be locally created and ignored. -Otherwise, if a type is present in the union profile but not present in a target, -it is deemed to be incompatible with that target. +The compatibility analysis compares a type used to both a target profile and a "union" profile +(containing all types available in *any* profile in the profile dir). If a type is not present in +the union profile, it is assumed to be locally created and ignored. Otherwise, if a type is present +in the union profile but not present in a target, it is deemed to be incompatible with that target. ## Configuration settings -| Configuration key | Meaning | Accepted values | Mandatory | Example | -| ----------------- | ------- | --------------- | --------- | ------- | -| `Enable` | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` | -| `TargetProfiles` | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` | -| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` | -| `IgnoreTypes` | Full names of types or type accelerators to ignore compatibility of in scripts | string[]: names of types to ignore | No (default: `@()`) | `@('System.Collections.ArrayList','string')` | +| Configuration key | Meaning | Accepted values | Mandatory | Example | +| ----------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `Enable` | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` | +| `TargetProfiles` | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` | +| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` | +| `IgnoreTypes` | Full names of types or type accelerators to ignore compatibility of in scripts | string[]: names of types to ignore | No (default: `@()`) | `@('System.Collections.ArrayList','string')` | An example configuration might look like: -```PowerShell +```powershell @{ Rules = @{ PSUseCompatibleTypes = @{ @@ -105,7 +115,7 @@ An example configuration might look like: Alternatively, you could provide a settings object as follows: -```PowerShell +```powershell PS> $settings = @{ Rules = @{ PSUseCompatibleTypes = @{ @@ -116,17 +126,17 @@ PS> $settings = @{ } PS> Invoke-ScriptAnalyzer -Settings $settings -ScriptDefinition '[System.Management.Automation.SemanticVersion]"1.18.0-rc1"' -RuleName Severity ScriptName Line Message --------- -------- ---------- ---- ------- -PSUseCompatibleTypes Warning 1 The type 'System.Management.Automation.SemanticVersion' is - not available by default in PowerShell version - '5.1.17763.316' on platform 'Microsoft Windows 10 Pro' +RuleName Severity ScriptName Line Message +-------- -------- ---------- ---- ------- +PSUseCompatibleTypes Warning 1 The type 'System.Management.Automation.SemanticVersion' is + not available by default in PowerShell version + '5.1.17763.316' on platform 'Microsoft Windows 10 Pro' ``` ## Suppression -Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a scriptblock -as with other rules. +Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a +scriptblock as with other rules. ```powershell [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleTypes", "")] diff --git a/RuleDocumentation/UseConsistentIndentation.md b/RuleDocumentation/UseConsistentIndentation.md index 81ff32ca8..48458a423 100644 --- a/RuleDocumentation/UseConsistentIndentation.md +++ b/RuleDocumentation/UseConsistentIndentation.md @@ -35,29 +35,38 @@ Indentation size in the number of space characters. Whether to increase indentation after a pipeline for multi-line statements. The settings are: -- IncreaseIndentationForFirstPipeline (default): Indent once after the first pipeline and keep this indentation. Example: -```powershell -foo | - bar | - baz -``` -- IncreaseIndentationAfterEveryPipeline: Indent more after the first pipeline and keep this indentation. Example: -```powershell -foo | - bar | - baz -``` +- IncreaseIndentationForFirstPipeline (default): Indent once after the first pipeline and keep this + indentation. Example: + + ```powershell + foo | + bar | + baz + ``` + +- IncreaseIndentationAfterEveryPipeline: Indent more after the first pipeline and keep this + indentation. Example: + + ```powershell + foo | + bar | + baz + ``` + - NoIndentation: Do not increase indentation. Example: -```powershell -foo | -bar | -baz -``` + + ```powershell + foo | + bar | + baz + ``` + - None: Do not change any existing pipeline indentation. #### Kind: string (Default value is `space`) -Represents the kind of indentation to be used. Possible values are: `space`, `tab`. If any invalid value is given, the property defaults to `space`. +Represents the kind of indentation to be used. Possible values are: `space`, `tab`. If any invalid +value is given, the property defaults to `space`. -`space` means `IndentationSize` number of `space` characters are used to provide one level of indentation. -`tab` means a tab character, `\t`. +`space` means `IndentationSize` number of `space` characters are used to provide one level of +indentation. `tab` means a tab character, `\t`. diff --git a/RuleDocumentation/UseConsistentWhitespace.md b/RuleDocumentation/UseConsistentWhitespace.md index 8d47809a6..999a16190 100644 --- a/RuleDocumentation/UseConsistentWhitespace.md +++ b/RuleDocumentation/UseConsistentWhitespace.md @@ -35,37 +35,49 @@ Enable or disable the rule during ScriptAnalyzer invocation. #### CheckInnerBrace: bool (Default value is `$true`) -Checks if there is a space after the opening brace and a space before the closing brace. E.g. `if ($true) { foo }` instead of `if ($true) {bar}`. +Checks if there is a space after the opening brace and a space before the closing brace. E.g. +`if ($true) { foo }` instead of `if ($true) {bar}`. #### CheckOpenBrace: bool (Default value is `$true`) -Checks if there is a space between a keyword and its corresponding open brace. E.g. `foo { }` instead of `foo{ }`. If an open brace is preceded by an open parenthesis, then no space is required. +Checks if there is a space between a keyword and its corresponding open brace. E.g. `foo { }` +instead of `foo{ }`. If an open brace is preceded by an open parenthesis, then no space is required. #### CheckOpenParen: bool (Default value is `$true`) -Checks if there is space between a keyword and its corresponding open parenthesis. E.g. `if (true)` instead of `if(true)`. +Checks if there is space between a keyword and its corresponding open parenthesis. E.g. `if (true)` +instead of `if(true)`. #### CheckOperator: bool (Default value is `$true`) -Checks if a binary or unary operator is surrounded on both sides by a space. E.g. `$x = 1` instead of `$x=1`. +Checks if a binary or unary operator is surrounded on both sides by a space. E.g. `$x = 1` instead +of `$x=1`. #### CheckSeparator: bool (Default value is `$true`) -Checks if a comma or a semicolon is followed by a space. E.g. `@(1, 2, 3)` or `@{a = 1; b = 2}` instead of `@(1,2,3)` or `@{a = 1;b = 2}`. +Checks if a comma or a semicolon is followed by a space. E.g. `@(1, 2, 3)` or `@{a = 1; b = 2}` +instead of `@(1,2,3)` or `@{a = 1;b = 2}`. #### CheckPipe: bool (Default value is `$true`) -Checks if a pipe is surrounded on both sides by a space but ignores redundant whitespace. E.g. `foo | bar` instead of `foo|bar`. +Checks if a pipe is surrounded on both sides by a space but ignores redundant whitespace. E.g. +`foo | bar` instead of `foo|bar`. #### CheckPipeForRedundantWhitespace : bool (Default value is `$false`) -Checks if a pipe is surrounded by redundant whitespace (i.e. more than 1 whitespace). E.g. `foo | bar` instead of `foo | bar`. +Checks if a pipe is surrounded by redundant whitespace (i.e. more than 1 whitespace). E.g. +`foo | bar` instead of `foo | bar`. #### CheckParameter: bool (Default value is `$false` at the moment due to the setting being new) -Checks if there is more than one space between parameters and values. E.g. `foo -bar $baz -bat` instead of `foo -bar $baz -bat`. This eliminates redundant whitespace that was probably added unintentionally. -The rule does not check for whitespace between parameter and value when the colon syntax `-ParameterName:$ParameterValue` is used as some users prefer either 0 or 1 whitespace in this case. +Checks if there is more than one space between parameters and values. E.g. `foo -bar $baz -bat` +instead of `foo -bar $baz -bat`. This eliminates redundant whitespace that was probably added +unintentionally. The rule does not check for whitespace between parameter and value when the colon +syntax `-ParameterName:$ParameterValue` is used as some users prefer either 0 or 1 whitespace in +this case. #### IgnoreAssignmentOperatorInsideHashTable: bool (Default value is `$false`) -When `CheckOperator` is set, ignore whitespace around assignment operators within multi-line hash tables. Set this option in order to use the `AlignAssignmentStatement` rule but still check whitespace around operators everywhere else. \ No newline at end of file +When `CheckOperator` is set, ignore whitespace around assignment operators within multi-line hash +tables. Set this option in order to use the `AlignAssignmentStatement` rule but still check +whitespace around operators everywhere else. \ No newline at end of file diff --git a/RuleDocumentation/UseCorrectCasing.md b/RuleDocumentation/UseCorrectCasing.md index 60a93f262..b5a1d1038 100644 --- a/RuleDocumentation/UseCorrectCasing.md +++ b/RuleDocumentation/UseCorrectCasing.md @@ -4,22 +4,26 @@ ## Description -This is a style/formatting rule. PowerShell is case insensitive where applicable. The casing of cmdlet names or parameters does not matter but this rule ensures that the casing matches for consistency and also because most cmdlets/parameters start with an upper case and using that improves readability to the human eye. +This is a style/formatting rule. PowerShell is case insensitive where applicable. The casing of +cmdlet names or parameters does not matter but this rule ensures that the casing matches for +consistency and also because most cmdlets/parameters start with an upper case and using that +improves readability to the human eye. ## How -Use exact casing of the cmdlet and its parameters, e.g. `Invoke-Command { 'foo' } -RunAsAdministrator`. +Use exact casing of the cmdlet and its parameters, e.g. +`Invoke-Command { 'foo' } -RunAsAdministrator`. ## Example ### Wrong -``` PowerShell +```powershell invoke-command { 'foo' } -runasadministrator ``` ### Correct -``` PowerShell +```powershell Invoke-Command { 'foo' } -RunAsAdministrator ``` diff --git a/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md b/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md index 28e7ee9ea..48e36991c 100644 --- a/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md +++ b/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md @@ -4,7 +4,8 @@ ## Description -Generally variables that are not used more than their assignments are considered wasteful and not needed. +Generally variables that are not used more than their assignments are considered wasteful and not +needed. ## How @@ -14,7 +15,7 @@ Remove the variables that are declared but not used. ### Wrong -``` PowerShell +```powershell function Test { $declaredVar = "Declared just for fun" @@ -25,7 +26,7 @@ function Test ### Correct -``` PowerShell +```powershell function Test { $declaredVar = "Declared just for fun" diff --git a/RuleDocumentation/UseLiteralInitializerForHashtable.md b/RuleDocumentation/UseLiteralInitializerForHashtable.md index 57f766b91..8014ff22e 100644 --- a/RuleDocumentation/UseLiteralInitializerForHashtable.md +++ b/RuleDocumentation/UseLiteralInitializerForHashtable.md @@ -4,28 +4,34 @@ ## Description -Creating a hashtable by either `[hashtable]::new()` or `New-Object -TypeName hashtable` will create a hashtable wherein the keys are looked-up in a case-sensitive manner, unless an `IEqualityComparer` object is passed as an argument. However, PowerShell is case-insensitive in nature and it is best to create hashtables with case-insensitive key look-up. This rule is intended to warn the author of the case-sensitive nature of the hashtable if he/she creates a hashtable using the `new` member or the `New-Object` cmdlet. +Creating a hashtable using `[hashtable]::new()` or `New-Object -TypeName hashtable` without passing +a `IEqualityComparer` object to the constructor creates a hashtable where the keys are looked-up in +a case-sensitive manner. However, PowerShell is case-insensitive in nature and it is best to create +hashtables with case-insensitive key look-up. + +This rule is intended to warn the author of the case-sensitive nature of the hashtable when created +using the `new` method or the `New-Object` cmdlet. ## How to Fix -Use the full cmdlet name and not an alias. +Create the hashtable using a literal hashtable expression. ## Example -### Wrong??? +### Wrong -``` PowerShell +```powershell $hashtable = [hashtable]::new() ``` -### Wrong??? +### Wrong -``` PowerShell +```powershell $hashtable = New-Object -TypeName hashtable ``` -### Correct: +### Correct -``` PowerShell +```powershell $hashtable = @{} ``` diff --git a/RuleDocumentation/UseOutputTypeCorrectly.md b/RuleDocumentation/UseOutputTypeCorrectly.md index c4c0d1892..c981000de 100644 --- a/RuleDocumentation/UseOutputTypeCorrectly.md +++ b/RuleDocumentation/UseOutputTypeCorrectly.md @@ -6,7 +6,8 @@ A command should return the same type as declared in `OutputType`. -You can get more details by running `Get-Help about_Functions_OutputTypeAttribute` command in Windows PowerShell. +You can get more details by running `Get-Help about_Functions_OutputTypeAttribute` command in +PowerShell. ## How @@ -16,7 +17,7 @@ Specify that the OutputType attribute lists and the types returned in the cmdlet ### Wrong -``` PowerShell +```powershell function Get-Foo { [CmdletBinding()] @@ -29,7 +30,7 @@ function Get-Foo ### Correct -``` PowerShell +```powershell function Get-Foo { [CmdletBinding()] diff --git a/RuleDocumentation/UsePSCredentialType.md b/RuleDocumentation/UsePSCredentialType.md index f44e8d9aa..07ffcb2ae 100644 --- a/RuleDocumentation/UsePSCredentialType.md +++ b/RuleDocumentation/UsePSCredentialType.md @@ -4,28 +4,29 @@ ## Description -If the cmdlet or function has a `Credential` parameter, the parameter must accept the `PSCredential` type. +If the cmdlet or function has a **Credential** parameter, the parameter must accept the +**PSCredential** type. ## How -Change the `Credential` parameter's type to be `PSCredential`. +Change the **Credential** parameter's type to be **PSCredential**. ## Example ### Wrong -``` PowerShell +```powershell function Credential([String]$Credential) { - ... + ... } ``` ### Correct -``` PowerShell +```powershell function Credential([PSCredential]$Credential) { - ... + ... } ``` diff --git a/RuleDocumentation/UseProcessBlockForPipelineCommand.md b/RuleDocumentation/UseProcessBlockForPipelineCommand.md index d66dc6f72..f0d5a4748 100644 --- a/RuleDocumentation/UseProcessBlockForPipelineCommand.md +++ b/RuleDocumentation/UseProcessBlockForPipelineCommand.md @@ -4,23 +4,25 @@ ## Description -Functions that support pipeline input should always handle parameter input in a process block. Unexpected behavior can result if input is handled directly in the body of a function where parameters declare pipeline support. +Functions that support pipeline input should always handle parameter input in a process block. +Unexpected behavior can result if input is handled directly in the body of a function where +parameters declare pipeline support. ## Example ### Wrong -``` PowerShell +```powershell Function Get-Number { - [CmdletBinding()] - Param( - [Parameter(ValueFromPipeline)] - [int] - $Number - ) - - $Number + [CmdletBinding()] + Param( + [Parameter(ValueFromPipeline)] + [int] + $Number + ) + + $Number } ``` @@ -33,20 +35,20 @@ PS C:\> 1..5 | Get-Number ### Correct -``` PowerShell +```powershell Function Get-Number { - [CmdletBinding()] - Param( - [Parameter(ValueFromPipeline)] - [int] - $Number - ) - - process - { - $Number - } + [CmdletBinding()] + Param( + [Parameter(ValueFromPipeline)] + [int] + $Number + ) + + process + { + $Number + } } ``` diff --git a/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md b/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md index 9b253e8fb..8835c77c0 100644 --- a/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md +++ b/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md @@ -7,14 +7,15 @@ Functions whose verbs change system state should support `ShouldProcess`. Verbs that should support `ShouldProcess`: -* `New` -* `Set` -* `Remove` -* `Start` -* `Stop` -* `Restart` -* `Reset` -* `Update` + +- `New` +- `Set` +- `Remove` +- `Start` +- `Stop` +- `Restart` +- `Reset` +- `Update` ## How @@ -24,30 +25,30 @@ Include the `SupportsShouldProcess` argument in the `CmdletBinding` attribute. ### Wrong -``` PowerShell - function Set-ServiceObject - { - [CmdletBinding()] - param - ( - [string] - $Parameter1 - ) - ... - } +```powershell +function Set-ServiceObject +{ + [CmdletBinding()] + param + ( + [string] + $Parameter1 + ) + ... +} ``` ### Correct -``` PowerShell - function Set-ServiceObject - { - [CmdletBinding(SupportsShouldProcess = $true)] - param - ( - [string] - $Parameter1 - ) - ... - } +```powershell +function Set-ServiceObject +{ + [CmdletBinding(SupportsShouldProcess = $true)] + param + ( + [string] + $Parameter1 + ) + ... +} ``` diff --git a/RuleDocumentation/UseSingularNouns.md b/RuleDocumentation/UseSingularNouns.md index 1966cd2a3..1ff3b8ba6 100644 --- a/RuleDocumentation/UseSingularNouns.md +++ b/RuleDocumentation/UseSingularNouns.md @@ -6,7 +6,8 @@ PowerShell team best practices state cmdlets should use singular nouns and not plurals. -**NOTE** This rule is not available in PowerShell Core due to the PluralizationService API that the rule uses internally. +**NOTE** This rule is not available in PowerShell Core due to the **PluralizationService** API that +the rule uses internally. ## How @@ -16,7 +17,7 @@ Change plurals to singular. ### Wrong -``` PowerShell +```powershell function Get-Files { ... @@ -25,7 +26,7 @@ function Get-Files ### Correct -``` PowerShell +```powershell function Get-File { ... diff --git a/RuleDocumentation/UseSupportsShouldProcess.md b/RuleDocumentation/UseSupportsShouldProcess.md index 5ae7b486f..c937cf0dd 100644 --- a/RuleDocumentation/UseSupportsShouldProcess.md +++ b/RuleDocumentation/UseSupportsShouldProcess.md @@ -1,23 +1,32 @@ # UseSupportsShouldProcess + **Severity Level: Warning** ## Description -This rule discourages manual declaration of `whatif` and `confirm` parameters in a function/cmdlet. These parameters are, however, provided automatically when a function declares a `CmdletBinding` attribute with `SupportsShouldProcess` as its named argument. Using `SupportsShouldProcess` no only provides these parameters but also some generic functionality that allows the function/cmdlet authors to provide the desired interactive experience while using the cmdlet. + +This rule discourages manual declaration of `WhatIf` and `Confirm` parameters in a function/cmdlet. +These parameters are, however, provided automatically when a function declares a `CmdletBinding` +attribute with `SupportsShouldProcess` as its named argument. Using `SupportsShouldProcess` no only +provides these parameters but also some generic functionality that allows the function/cmdlet +authors to provide the desired interactive experience while using the cmdlet. ## Example + ### Wrong: -```PowerShell + +```powershell function foo { param( $param1, - $confirm, - $whatif + $Confirm, + $WhatIf ) } ``` ### Correct: -```PowerShell + +```powershell function foo { [CmdletBinding(SupportsShouldProcess)] param( diff --git a/RuleDocumentation/UseToExportFieldsInManifest.md b/RuleDocumentation/UseToExportFieldsInManifest.md index f90f6a383..4358756d6 100644 --- a/RuleDocumentation/UseToExportFieldsInManifest.md +++ b/RuleDocumentation/UseToExportFieldsInManifest.md @@ -4,13 +4,16 @@ ## Description -To improve the performance of module auto-discovery, module manifests should not use wildcards (`'*'`) or null (`$null`) in the following entries: -* `AliasesToExport` -* `CmdletsToExport` -* `FunctionsToExport` -* `VariablesToExport` +To improve the performance of module auto-discovery, module manifests should not use wildcards +(`'*'`) or null (`$null`) in the following entries: -The use of wildcards or null has the potential to cause PowerShell to perform expensive work to analyse a module during module auto-discovery. +- `AliasesToExport` +- `CmdletsToExport` +- `FunctionsToExport` +- `VariablesToExport` + +Using wildcards or null has causes PowerShell to perform expensive work to analyze a module during +module auto-discovery. ## How @@ -22,28 +25,29 @@ Suppose there are no functions in your module to export. Then, ### Wrong -``` PowerShell +```powershell FunctionsToExport = $null ``` ### Correct -``` PowerShell +```powershell FunctionToExport = @() ``` ## Example -Suppose there are only two functions in your module, ```Get-Foo``` and ```Set-Foo``` that you want to export. Then, +Suppose there are only two functions in your module, `Get-Foo` and `Set-Foo` that you want to +export. Then, ### Wrong -``` PowerShell +```powershell FunctionsToExport = '*' ``` ### Correct -``` PowerShell +```powershell FunctionToExport = @(Get-Foo, Set-Foo) ``` diff --git a/RuleDocumentation/UseUTF8EncodingForHelpFile.md b/RuleDocumentation/UseUTF8EncodingForHelpFile.md index 30e9691d4..b1ef86e98 100644 --- a/RuleDocumentation/UseUTF8EncodingForHelpFile.md +++ b/RuleDocumentation/UseUTF8EncodingForHelpFile.md @@ -4,4 +4,4 @@ ## Description -Check if help file uses utf8 encoding \ No newline at end of file +Check if help file uses UTF-8 encoding. diff --git a/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md b/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md index d1ba06cf8..419faae28 100644 --- a/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md +++ b/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md @@ -1,65 +1,64 @@ -# UseUsingScopeModifierInNewRunspaces - -**Severity Level: Warning** - -## Description - -If a ScriptBlock is intended to be run in a new RunSpace, variables inside it should use $using: scope modifier, or be initialized within the ScriptBlock. -This applies to: - -- Invoke-Command * -- Workflow { InlineScript {}} -- Foreach-Object ** -- Start-Job -- Start-ThreadJob -- The `Script` resource in DSC configurations, specifically for the `GetScript`, `TestScript` and `SetScript` properties - -\* Only with the -ComputerName or -Session parameter. -\*\* Only with the -Parallel parameter - -## How to Fix - -Within the ScriptBlock, instead of just using a variable from the parent scope, you have to add the `using:` scope modifier to it. - -## Example - -### Wrong - -```PowerShell -$var = "foo" -1..2 | ForEach-Object -Parallel { $var } -``` - -### Correct - -```PowerShell -$var = "foo" -1..2 | ForEach-Object -Parallel { $using:var } -``` - -## More correct examples - -```powershell -$bar = "bar" -Invoke-Command -ComputerName "foo" -ScriptBlock { $using:bar } -``` - -```powershell -$bar = "bar" -$s = New-PSSession -ComputerName "foo" -Invoke-Command -Session $s -ScriptBlock { $using:bar } -``` - -```powershell -# Remark: Workflow is supported on Windows PowerShell only -Workflow { - $foo = "foo" - InlineScript { $using:foo } -} -``` - -```powershell -$foo = "foo" -Start-ThreadJob -ScriptBlock { $using:foo } -Start-Job -ScriptBlock {$using:foo } +# UseUsingScopeModifierInNewRunspaces + +**Severity Level: Warning** + +## Description + +If a scriptblock is intended to be run in a new runspace, variables inside it should use the +`$using:` scope modifier, or be initialized within the scriptblock. This applies to: + +- `Invoke-Command`- Only with the **ComputerName** or **Session** parameter. +- `Workflow { InlineScript {} }` +- `Foreach-Object` - Only with the **Parallel** parameter +- `Start-Job` +- `Start-ThreadJob` +- The `Script` resource in DSC configurations, specifically for the `GetScript`, `TestScript` and + `SetScript` properties. + +## How to Fix + +Within the ScriptBlock, instead of just using a variable from the parent scope, you have to add the +`using:` scope modifier to it. + +## Example + +### Wrong + +```powershell +$var = "foo" +1..2 | ForEach-Object -Parallel { $var } +``` + +### Correct + +```powershell +$var = "foo" +1..2 | ForEach-Object -Parallel { $using:var } +``` + +## More correct examples + +```powershell +$bar = "bar" +Invoke-Command -ComputerName "foo" -ScriptBlock { $using:bar } +``` + +```powershell +$bar = "bar" +$s = New-PSSession -ComputerName "foo" +Invoke-Command -Session $s -ScriptBlock { $using:bar } +``` + +```powershell +# Remark: Workflow is supported on Windows PowerShell only +Workflow { + $foo = "foo" + InlineScript { $using:foo } +} +``` + +```powershell +$foo = "foo" +Start-ThreadJob -ScriptBlock { $using:foo } +Start-Job -ScriptBlock {$using:foo } ``` \ No newline at end of file diff --git a/ScriptRuleDocumentation.md b/ScriptRuleDocumentation.md index 9c5adcf4e..36979820a 100644 --- a/ScriptRuleDocumentation.md +++ b/ScriptRuleDocumentation.md @@ -10,7 +10,7 @@ The purpose of this documentation is to serve as a basic guide on creating your - 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 +```powershell <# .SYNOPSIS Name of your rule. @@ -25,13 +25,13 @@ The purpose of this documentation is to serve as a basic guide on creating your - Output type should be DiagnosticRecord: -``` PowerShell +```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 +```powershell Param ( [Parameter(Mandatory = $true)] @@ -41,7 +41,7 @@ Param ) ``` -``` PowerShell +```powershell Param ( [Parameter(Mandatory = $true)] @@ -53,7 +53,7 @@ Param - DiagnosticRecord should have at least four properties: Message, Extent, RuleName and Severity -``` PowerShell +```powershell $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{ "Message" = "This is a sample rule" "Extent" = $ast.Extent @@ -87,13 +87,13 @@ $suggestedCorrections.add($correctionExtent) | out-null - Make sure you export the function(s) at the end of the script using Export-ModuleMember -``` PowerShell +```powershell Export-ModuleMember -Function (FunctionName) ``` ### Example -``` PowerShell +```powershell <# .SYNOPSIS Uses #Requires -RunAsAdministrator instead of your own methods.