From 8a5bebb66bad238ea84cc7aa3662152240618094 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 6 May 2018 17:04:13 -0600 Subject: [PATCH 01/12] Fix table to refer to existing md files, add col for Configurable --- RuleDocumentation/README.md | 107 +++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md index 443d5bc26..666be9e87 100644 --- a/RuleDocumentation/README.md +++ b/RuleDocumentation/README.md @@ -2,54 +2,59 @@ ## Table of Contents -| Rule | Severity | -|------|----------------------------------| -|[AvoidAlias](./AvoidAlias.md) | Warning | -|[AvoidDefaultTrueValueSwitchParameter](./AvoidDefaultTrueValueSwitchParameter.md) | Warning| -|[AvoidEmptyCatchBlock](./AvoidEmptyCatchBlock.md) | Warning| -|[AvoidGlobalVars](./AvoidGlobalVars.md) | Warning| -|[AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning| -|[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning| -|[AvoidReservedCharInCmdlet](./AvoidReservedCharInCmdlet.md) | Error | -|[AvoidReservedParams](./AvoidReservedParams.md) | Error | -|[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning| -|[AvoidTrapStatement](./AvoidTrapStatement.md) | Warning| -|[AvoidUninitializedVariable](./AvoidUninitializedVariable.md) | Warning| -|[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | -|[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | -|[AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning| -|[AvoidUsingFilePath](./AvoidUsingFilePath.md) | Error | -|[AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning| -|[AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning| -|[AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning| -|[AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | -|[AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning| -|[AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning| -|[DscExamplesPresent](./DscExamplesPresent.md) | Information | -|[DscTestsPresent](./DscTestsPresent.md) | Information | -|[MissingModuleManifestField](./MissingModuleManifestField.md) | Warning| -|[PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md) | Warning| -|[ProvideCommentHelp](./ProvideCommentHelp.md) | Information| -|[ProvideDefaultParameterValue](./ProvideDefaultParameterValue.md) | Warning| -|[ProvideVerboseMessage](./ProvideVerboseMessage.md) | Information | -|[ReturnCorrectTypeDSCFunctions](./ReturnCorrectTypeDSCFunctions.md) | Information | -|[UseApprovedVerbs](./UseApprovedVerbs.md) | Warning| -|[UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning| -|[UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning| -|[UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning| -|[UseIdenticalMandatoryParametersDSC](./UseIdenticalMandatoryParametersDSC.md) | Error | -|[UseIdenticalParametersDSC](./UseIdenticalParametersDSC.md) | Error | -|[UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | -|[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information| -|[UsePSCredentialType](./UsePSCredentialType.md) | Warning| -|[UseShouldProcessCorrectly](./UseShouldProcessCorrectly.md) | Warning| -|[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning| -|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning| -|[UseSingularNouns](./UseSingularNouns.md) | Warning| -|[UseStandardDSCFunctionsInResource](./UseStandardDSCFunctionsInResource.md) | Error | -|[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning| -|[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning| -|[PlaceOpenBrace](./PlaceOpenBrace.md) | Warning| -|[PlaceCloseBrace](./PlaceCloseBrace.md) | Warning| -|[UseConsistentIndentation](./UseConsistentIndentation.md) | Warning| -|[UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning| +| Rule | Severity | Configurable | +|------|----------------------------------|--------------| +|[AvoidDefaultTrueValueSwitchParameter](./AvoidDefaultTrueValueSwitchParameter.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 | | +|[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | | +|[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | | +|[AvoidTrapStatement](./AvoidTrapStatement.md) | Warning | | +|[AvoidUninitializedVariable](./AvoidUninitializedVariable.md) | Warning | | +|[AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes | +|[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | | +|[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | | +|[AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning | | +|[AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md) | Warning | | +|[AvoidUsingFilePath](./AvoidUsingFilePath.md) | Error | | +|[AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning | | +|[AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning | | +|[AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning | | +|[AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | | +|[AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning | | +|[AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning | | +|[DscExamplesPresent](./DscExamplesPresent.md) | Information | | +|[DscTestsPresent](./DscTestsPresent.md) | Information | | +|[MisleadingBacktick](./MisleadingBacktick.md) | Warning | | +|[MissingModuleManifestField](./MissingModuleManifestField.md) | Warning | | +|[PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md) | Warning | | +|[ProvideCommentHelp](./ProvideCommentHelp.md) | Information | Yes | +|[ProvideDefaultParameterValue](./ProvideDefaultParameterValue.md) | Warning | | +|[ReservedCharInCmdlet](./ReservedCharInCmdlet.md) | Error | | +|[ReservedParams](./ReservedParams.md) | Error | | +|[ReturnCorrectTypeDSCFunctions](./ReturnCorrectTypeDSCFunctions.md) | Information | | +|[ShouldProcess](./ShouldProcess.md) | Error | | +|[StandardDSCFunctionsInResource](./StandardDSCFunctionsInResource.md) | Error | | +|[UseApprovedVerbs](./UseApprovedVerbs.md) | Warning | | +|[UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning | | +|[UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning | | +|[UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning | | +|[UseIdenticalMandatoryParametersDSC](./UseIdenticalMandatoryParametersDSC.md) | Error | | +|[UseIdenticalParametersDSC](./UseIdenticalParametersDSC.md) | Error | | +|[UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | | +|[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | | +|[UsePSCredentialType](./UsePSCredentialType.md) | Warning | | +|[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | | +|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | | +|[UseSingularNouns](./UseSingularNouns.md) | Warning | | +|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Error | | +|[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | | +|[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning | Yes | +|[PlaceOpenBrace](./PlaceOpenBrace.md) | Warning | Yes | +|[PlaceCloseBrace](./PlaceCloseBrace.md) | Warning | Yes | +|[UseConsistentIndentation](./UseConsistentIndentation.md) | Warning | Yes | +|[UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning | Yes | From dbc515751f48b9c02f9ba9756bb3661fad41a154 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sun, 13 May 2018 22:03:10 -0600 Subject: [PATCH 02/12] Remove deprecated rules, rename to match actual rule sans PS prefix --- RuleDocumentation/AvoidTrapStatement.md | 48 ------------------- .../AvoidUninitializedVariable.md | 34 ------------- RuleDocumentation/AvoidUsingFilePath.md | 47 ------------------ ...lesPresent.md => DSCDscExamplesPresent.md} | 0 ...cTestsPresent.md => DSCDscTestsPresent.md} | 0 ...> DSCReturnCorrectTypesForDSCFunctions.md} | 0 ...d => DSCStandardDSCFunctionsInResource.md} | 0 ...CUseIdenticalMandatoryParametersForDSC.md} | 0 ....md => DSCUseIdenticalParametersForDSC.md} | 0 ...d => DSCUseVerboseMessageInDSCResource.md} | 0 RuleDocumentation/UseSingularNouns.md | 31 ------------ 11 files changed, 160 deletions(-) delete mode 100644 RuleDocumentation/AvoidTrapStatement.md delete mode 100644 RuleDocumentation/AvoidUninitializedVariable.md delete mode 100644 RuleDocumentation/AvoidUsingFilePath.md rename RuleDocumentation/{DscExamplesPresent.md => DSCDscExamplesPresent.md} (100%) rename RuleDocumentation/{DscTestsPresent.md => DSCDscTestsPresent.md} (100%) rename RuleDocumentation/{ReturnCorrectTypesForDSCFunctions.md => DSCReturnCorrectTypesForDSCFunctions.md} (100%) rename RuleDocumentation/{StandardDSCFunctionsInResource.md => DSCStandardDSCFunctionsInResource.md} (100%) rename RuleDocumentation/{UseIdenticalMandatoryParametersForDSC.md => DSCUseIdenticalMandatoryParametersForDSC.md} (100%) rename RuleDocumentation/{UseIdenticalParametersForDSC.md => DSCUseIdenticalParametersForDSC.md} (100%) rename RuleDocumentation/{UseVerboseMessageInDSCResource.md => DSCUseVerboseMessageInDSCResource.md} (100%) delete mode 100644 RuleDocumentation/UseSingularNouns.md diff --git a/RuleDocumentation/AvoidTrapStatement.md b/RuleDocumentation/AvoidTrapStatement.md deleted file mode 100644 index 69f5d694d..000000000 --- a/RuleDocumentation/AvoidTrapStatement.md +++ /dev/null @@ -1,48 +0,0 @@ -# AvoidTrapStatement - -**Severity Level: Warning** - -## Description - -The `Trap` keyword specifies a list of statements to run when a terminating error occurs. - -Trap statements handle the terminating errors and allow execution of the script or function to continue instead of stopping. - -Traps are intended for the use of administrators and not for script and cmdlet developers. PowerShell scripts and cmdlets should make use -of `try{} catch{} finally{}` statements. - -## How - -Replace `Trap` statements with `try{} catch{} finally{}` statements. - -## Example - -### Wrong - -``` PowerShell -function Test-Trap -{ - trap {"Error found: $_"} -} -``` - -### Correct - -``` PowerShell -function Test-Trap -{ - try - { - $a = New-Object "NonExistentObjectType" - $a | Get-Member - } - catch [System.Exception] - { - "Found error" - } - finally - { - "End the script" - } - } - ``` diff --git a/RuleDocumentation/AvoidUninitializedVariable.md b/RuleDocumentation/AvoidUninitializedVariable.md deleted file mode 100644 index 8150f006a..000000000 --- a/RuleDocumentation/AvoidUninitializedVariable.md +++ /dev/null @@ -1,34 +0,0 @@ -# AvoidUninitializedVariable - -**Severity Level: Warning** - -## 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. - -All non-global variables must be initialized, otherwise potential bugs could be introduced. - -## How - -Initialize non-global variables. - -## Example - -### Wrong - -``` PowerShell -function NotGlobal { - $localVars = "Localization?" - $uninitialized - Write-Output $uninitialized -} -``` - -### Correct - -``` PowerShell -function NotGlobal { - $localVars = "Localization?" - Write-Output $localVars -} -``` diff --git a/RuleDocumentation/AvoidUsingFilePath.md b/RuleDocumentation/AvoidUsingFilePath.md deleted file mode 100644 index 1cb13aa16..000000000 --- a/RuleDocumentation/AvoidUsingFilePath.md +++ /dev/null @@ -1,47 +0,0 @@ -# AvoidUsingFilePath - -**Severity Level: Error** - -## Description - -If a file path is used in a script that refers to a file on the computer or on the shared network, this could expose sensitive information or result in availability issues. - -Care should be taken to ensure that no computer or network paths are hard coded, instead non-rooted paths should be used. - -## How - -Ensure that no network paths are hard coded and that file paths are non-rooted. - -## Example - -### Wrong - -``` PowerShell -Function Get-MyCSVFile -{ - $FileContents = Get-FileContents -Path "\\scratch2\scratch\" - ... -} - -Function Write-Documentation -{ - Write-Warning "E:\Code" - ... -} -``` - -### Correct - -``` PowerShell -Function Get-MyCSVFile ($NetworkPath) -{ - $FileContents = Get-FileContents -Path $NetworkPath - ... -} - -Function Write-Documentation -{ - Write-Warning "..\Code" - ... -} -``` diff --git a/RuleDocumentation/DscExamplesPresent.md b/RuleDocumentation/DSCDscExamplesPresent.md similarity index 100% rename from RuleDocumentation/DscExamplesPresent.md rename to RuleDocumentation/DSCDscExamplesPresent.md diff --git a/RuleDocumentation/DscTestsPresent.md b/RuleDocumentation/DSCDscTestsPresent.md similarity index 100% rename from RuleDocumentation/DscTestsPresent.md rename to RuleDocumentation/DSCDscTestsPresent.md diff --git a/RuleDocumentation/ReturnCorrectTypesForDSCFunctions.md b/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md similarity index 100% rename from RuleDocumentation/ReturnCorrectTypesForDSCFunctions.md rename to RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md diff --git a/RuleDocumentation/StandardDSCFunctionsInResource.md b/RuleDocumentation/DSCStandardDSCFunctionsInResource.md similarity index 100% rename from RuleDocumentation/StandardDSCFunctionsInResource.md rename to RuleDocumentation/DSCStandardDSCFunctionsInResource.md diff --git a/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md b/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md similarity index 100% rename from RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md rename to RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md diff --git a/RuleDocumentation/UseIdenticalParametersForDSC.md b/RuleDocumentation/DSCUseIdenticalParametersForDSC.md similarity index 100% rename from RuleDocumentation/UseIdenticalParametersForDSC.md rename to RuleDocumentation/DSCUseIdenticalParametersForDSC.md diff --git a/RuleDocumentation/UseVerboseMessageInDSCResource.md b/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md similarity index 100% rename from RuleDocumentation/UseVerboseMessageInDSCResource.md rename to RuleDocumentation/DSCUseVerboseMessageInDSCResource.md diff --git a/RuleDocumentation/UseSingularNouns.md b/RuleDocumentation/UseSingularNouns.md deleted file mode 100644 index 1d7c20d31..000000000 --- a/RuleDocumentation/UseSingularNouns.md +++ /dev/null @@ -1,31 +0,0 @@ -# UseSingularNouns - -**Severity Level: Warning** - -## Description - -PowerShell team best practices state cmdlets should use singular nouns and not plurals. - -## How - -Change plurals to singular. - -## Example - -### Wrong - -``` PowerShell -function Get-Files -{ - ... -} -``` - -### Correct - -``` PowerShell -function Get-File -{ - ... -} -``` From d6310acdc87f64b3325b89ffbd28061b1122e6b9 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Tue, 15 May 2018 19:46:56 -0600 Subject: [PATCH 03/12] Add Pester tests for rule doc files, add back UseSingularNouns.md file --- RuleDocumentation/UseSingularNouns.md | 31 +++++++++++++++++++ .../Docmentation/RuleDocumentation.tests.ps1 | 23 ++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 RuleDocumentation/UseSingularNouns.md create mode 100644 Tests/Docmentation/RuleDocumentation.tests.ps1 diff --git a/RuleDocumentation/UseSingularNouns.md b/RuleDocumentation/UseSingularNouns.md new file mode 100644 index 000000000..c123bdf43 --- /dev/null +++ b/RuleDocumentation/UseSingularNouns.md @@ -0,0 +1,31 @@ +# UseSingularNouns + +**Severity Level: Warning** + +## Description + +PowerShell team best practices state cmdlets should use singular nouns and not plurals. + +## How + +Change plurals to singular. + +## Example + +### Wrong + +``` PowerShell +function Get-Files +{ + ... +} +``` + +### Correct + +``` PowerShell +function Get-File +{ + ... +} +``` diff --git a/Tests/Docmentation/RuleDocumentation.tests.ps1 b/Tests/Docmentation/RuleDocumentation.tests.ps1 new file mode 100644 index 000000000..3fd867b34 --- /dev/null +++ b/Tests/Docmentation/RuleDocumentation.tests.ps1 @@ -0,0 +1,23 @@ +$directory = Split-Path -Parent $MyInvocation.MyCommand.Path +$testRootDirectory = Split-Path -Parent $directory +$repoRootDirectory = Split-Path -Parent $testRootDirectory +$ruleDocDirectory = Join-Path $repoRootDirectory RuleDocumentation + +Import-Module PSScriptAnalyzer +Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1") + +Describe "Validate rule documentation files" { + BeforeAll { + $docs = Get-ChildItem $ruleDocDirectory/*.md -Exclude README.md | + ForEach-Object { "PS" + $_.BaseName} | Sort-Object + $rules = Get-ScriptAnalyzerRule | ForEach-Object RuleName | Sort-Object + $res = Compare-Object -ReferenceObject $rules -DifferenceObject $docs + } + It "Every rule must have a rule documentation file" { + Write-Host $res + $res | Where-Object SideIndicator -eq "<=" | Foreach-Object InputObject | Should -BeNullOrEmpty + } + It "Every rule documentation file must have a rule" { + $res | Where-Object SideIndicator -eq "=>" | Foreach-Object InputObject | Should -BeNullOrEmpty + } +} From 7c0576396b9b115289c23068ad814a4beca3ae9e Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Tue, 15 May 2018 21:20:07 -0600 Subject: [PATCH 04/12] Add Pester tests for verifying rule doc README.md file --- RuleDocumentation/README.md | 25 +++++------ .../Docmentation/RuleDocumentation.tests.ps1 | 43 ++++++++++++++++--- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md index 666be9e87..67b7b9f3a 100644 --- a/RuleDocumentation/README.md +++ b/RuleDocumentation/README.md @@ -4,7 +4,7 @@ | Rule | Severity | Configurable | |------|----------------------------------|--------------| -|[AvoidDefaultTrueValueSwitchParameter](./AvoidDefaultTrueValueSwitchParameter.md) | Warning | | +|[AlignAssignmentStatement](./AlignAssignmentStatement.md) | Warning | | |[AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | | |[AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | | |[AvoidGlobalAliases](./AvoidGlobalAliases.md) | Warning | | @@ -13,48 +13,45 @@ |[AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning | | |[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | | |[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | | -|[AvoidTrapStatement](./AvoidTrapStatement.md) | Warning | | -|[AvoidUninitializedVariable](./AvoidUninitializedVariable.md) | Warning | | |[AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes | |[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | | |[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | | |[AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning | | |[AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md) | Warning | | -|[AvoidUsingFilePath](./AvoidUsingFilePath.md) | Error | | |[AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning | | |[AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning | | |[AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning | | |[AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | | |[AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning | | |[AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning | | -|[DscExamplesPresent](./DscExamplesPresent.md) | Information | | -|[DscTestsPresent](./DscTestsPresent.md) | Information | | +|[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 | | |[ProvideCommentHelp](./ProvideCommentHelp.md) | Information | Yes | -|[ProvideDefaultParameterValue](./ProvideDefaultParameterValue.md) | Warning | | -|[ReservedCharInCmdlet](./ReservedCharInCmdlet.md) | Error | | +|[ReservedCmdletChar](./ReservedCmdletChar.md) | Error | | |[ReservedParams](./ReservedParams.md) | Error | | -|[ReturnCorrectTypeDSCFunctions](./ReturnCorrectTypeDSCFunctions.md) | Information | | |[ShouldProcess](./ShouldProcess.md) | Error | | -|[StandardDSCFunctionsInResource](./StandardDSCFunctionsInResource.md) | Error | | |[UseApprovedVerbs](./UseApprovedVerbs.md) | Warning | | |[UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning | | |[UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning | | |[UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning | | -|[UseIdenticalMandatoryParametersDSC](./UseIdenticalMandatoryParametersDSC.md) | Error | | -|[UseIdenticalParametersDSC](./UseIdenticalParametersDSC.md) | Error | | |[UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | | |[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | | |[UsePSCredentialType](./UsePSCredentialType.md) | Warning | | |[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | | -|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | | |[UseSingularNouns](./UseSingularNouns.md) | Warning | | -|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Error | | +|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | | |[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | | |[UseCompatibleCmdlets](./UseCompatibleCmdlets.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 | | diff --git a/Tests/Docmentation/RuleDocumentation.tests.ps1 b/Tests/Docmentation/RuleDocumentation.tests.ps1 index 3fd867b34..8e6279609 100644 --- a/Tests/Docmentation/RuleDocumentation.tests.ps1 +++ b/Tests/Docmentation/RuleDocumentation.tests.ps1 @@ -11,13 +11,46 @@ Describe "Validate rule documentation files" { $docs = Get-ChildItem $ruleDocDirectory/*.md -Exclude README.md | ForEach-Object { "PS" + $_.BaseName} | Sort-Object $rules = Get-ScriptAnalyzerRule | ForEach-Object RuleName | Sort-Object - $res = Compare-Object -ReferenceObject $rules -DifferenceObject $docs + $rulesDocsDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $docs -SyncWindow 25 + + $readmeLinks = @{} + $readmeRules = Get-Content -LiteralPath $ruleDocDirectory/README.md | + Foreach-Object { if ($_ -match '^\s*\|\s*\[([^]]+)\]\(([^)]+)\)\s*\|') { + $ruleName = $matches[1] + $readmeLinks["$ruleName"] = $matches[2] + "PS${ruleName}" + }} | + Sort-Object + $rulesReadmeDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $readmeRules -SyncWindow 25 } + It "Every rule must have a rule documentation file" { - Write-Host $res - $res | Where-Object SideIndicator -eq "<=" | Foreach-Object InputObject | Should -BeNullOrEmpty + $rulesDocsDiff | Where-Object SideIndicator -eq "<=" | Foreach-Object InputObject | Should -BeNullOrEmpty + } + It "Every rule documentation file must have a corresponding rule" { + $rulesDocsDiff | Where-Object SideIndicator -eq "=>" | Foreach-Object InputObject | Should -BeNullOrEmpty + } + + It "Every rule must have an entry in the rule documentation README.md file" { + $rulesReadmeDiff | Where-Object SideIndicator -eq "<=" | Foreach-Object InputObject | Should -BeNullOrEmpty + } + It "Every entry in the rule documentation README.md file must correspond to a rule" { + $rulesReadmeDiff | Where-Object SideIndicator -eq "=>" | Foreach-Object InputObject | Should -BeNullOrEmpty + } + + It "Every entry in the rule documentation README.md file must have a valid link to the documentation file" { + foreach ($key in $readmeLinks.Keys) { + $link = $readmeLinks[$key] + $filePath = Join-Path $ruleDocDirectory $link + $filePath | Should -Exist + } } - It "Every rule documentation file must have a rule" { - $res | Where-Object SideIndicator -eq "=>" | Foreach-Object InputObject | Should -BeNullOrEmpty + It "Every rule name in the rule documentation README.md file must match the documentation file's basename" { + foreach ($key in $readmeLinks.Keys) { + $link = $readmeLinks[$key] + $filePath = Join-Path $ruleDocDirectory $link + $fileName = Split-Path $filePath -Leaf + $fileName | Should -BeExactly "${key}.md" + } } } From 968bea75820c3691827755f2d51e0976a3fd9c7d Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 17 May 2018 07:35:15 +0100 Subject: [PATCH 05/12] fix typo in documentation folder, remove redundant ipmo call new tests in CI and add to docs --- README.md | 12 +++--------- .../RuleDocumentation.tests.ps1 | 1 - tools/appveyor.psm1 | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) rename Tests/{Docmentation => Documentation}/RuleDocumentation.tests.ps1 (98%) diff --git a/README.md b/README.md index 19feea818..355c28375 100644 --- a/README.md +++ b/README.md @@ -158,16 +158,10 @@ 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) is installed * Copy `path/to/PSScriptAnalyzer/out/PSScriptAnalyzer` to a folder in `PSModulePath` -* Go the Tests folder in your local repository -* Run Engine Tests: +* In the root folder of your local repository, run: ``` PowerShell -cd /path/to/PSScriptAnalyzer/Tests/Engine -Invoke-Pester -``` -* Run Tests for Built-in rules: -``` PowerShell -cd /path/to/PSScriptAnalyzer/Tests/Rules -Invoke-Pester +$testScripts = ".\Tests\Engine",".\Tests\Rules",".\Tests\Documentation" +Invoke-Pester -Script $testScripts ``` [Back to ToC](#table-of-contents) diff --git a/Tests/Docmentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 similarity index 98% rename from Tests/Docmentation/RuleDocumentation.tests.ps1 rename to Tests/Documentation/RuleDocumentation.tests.ps1 index 8e6279609..f6b09912d 100644 --- a/Tests/Docmentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -3,7 +3,6 @@ $testRootDirectory = Split-Path -Parent $directory $repoRootDirectory = Split-Path -Parent $testRootDirectory $ruleDocDirectory = Join-Path $repoRootDirectory RuleDocumentation -Import-Module PSScriptAnalyzer Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1") Describe "Validate rule documentation files" { diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index 0625dea33..146052a55 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -78,7 +78,7 @@ function Invoke-AppveyorTest { $modulePath = $env:PSModulePath.Split([System.IO.Path]::PathSeparator) | Where-Object { Test-Path $_} | Select-Object -First 1 Copy-Item "${CheckoutPath}\out\PSScriptAnalyzer" "$modulePath\" -Recurse -Force $testResultsFile = ".\TestResults.xml" - $testScripts = "${CheckoutPath}\Tests\Engine","${CheckoutPath}\Tests\Rules" + $testScripts = "${CheckoutPath}\Tests\Engine","${CheckoutPath}\Tests\Rules","${CheckoutPath}\Tests\Documentation" $testResults = Invoke-Pester -Script $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile -PassThru (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}", (Resolve-Path $testResultsFile)) if ($testResults.FailedCount -gt 0) { From 9172766da4da693e8db3ddc123149b0cf31f0114 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 17 May 2018 20:53:40 +0100 Subject: [PATCH 06/12] Add rules that will be present in 1.17 and fix typo in md file name --- ...rator.md => PossibleIncorrectUsageOfAssignmentOperator.md} | 0 RuleDocumentation/README.md | 4 ++++ 2 files changed, 4 insertions(+) rename RuleDocumentation/{PossibleIncorrectUsageOAssignmentOperator.md => PossibleIncorrectUsageOfAssignmentOperator.md} (100%) diff --git a/RuleDocumentation/PossibleIncorrectUsageOAssignmentOperator.md b/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md similarity index 100% rename from RuleDocumentation/PossibleIncorrectUsageOAssignmentOperator.md rename to RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md index 0e19153cf..efd139b7d 100644 --- a/RuleDocumentation/README.md +++ b/RuleDocumentation/README.md @@ -5,6 +5,7 @@ | Rule | Severity | Configurable | |------|----------------------------------|--------------| |[AlignAssignmentStatement](./AlignAssignmentStatement.md) | Warning | | +|[AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md) | Warning | | |[AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | | |[AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | | |[AvoidGlobalAliases](./AvoidGlobalAliases.md) | Warning | | @@ -21,6 +22,7 @@ |[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 | | @@ -34,6 +36,8 @@ |[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 | | From 0f51b7908f5468af5e3419a224baf4f289f7d443 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 17 May 2018 20:59:04 +0100 Subject: [PATCH 07/12] remove redundant import of PSScriptAnalyzerTestHelper test helper module in documentation test --- Tests/Documentation/RuleDocumentation.tests.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 index f6b09912d..9e69ed5c7 100644 --- a/Tests/Documentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -3,8 +3,6 @@ $testRootDirectory = Split-Path -Parent $directory $repoRootDirectory = Split-Path -Parent $testRootDirectory $ruleDocDirectory = Join-Path $repoRootDirectory RuleDocumentation -Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1") - Describe "Validate rule documentation files" { BeforeAll { $docs = Get-ChildItem $ruleDocDirectory/*.md -Exclude README.md | @@ -44,6 +42,7 @@ Describe "Validate rule documentation files" { $filePath | Should -Exist } } + It "Every rule name in the rule documentation README.md file must match the documentation file's basename" { foreach ($key in $readmeLinks.Keys) { $link = $readmeLinks[$key] From cfbd65931c221fb788a01cae0d63154a25f49917 Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Fri, 18 May 2018 18:25:27 -0600 Subject: [PATCH 08/12] Fix doc tests for PS v4 and PS Core This commit removes rules that aren't available on these versions --- Tests/Documentation/RuleDocumentation.tests.ps1 | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 index 9e69ed5c7..e312ca0ad 100644 --- a/Tests/Documentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -7,8 +7,8 @@ Describe "Validate rule documentation files" { BeforeAll { $docs = Get-ChildItem $ruleDocDirectory/*.md -Exclude README.md | ForEach-Object { "PS" + $_.BaseName} | Sort-Object + $rules = Get-ScriptAnalyzerRule | ForEach-Object RuleName | Sort-Object - $rulesDocsDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $docs -SyncWindow 25 $readmeLinks = @{} $readmeRules = Get-Content -LiteralPath $ruleDocDirectory/README.md | @@ -18,6 +18,20 @@ Describe "Validate rule documentation files" { "PS${ruleName}" }} | Sort-Object + + # Remove rules from the diff list that aren't supported on PSCore + if (($PSVersionTable.PSVersion.Major -ge 6) -and ($PSVersionTable.PSEdition -eq "Core")) + { + $RulesNotSupportedInNetstandard2 = @("PSUseSingularNouns") + $docs = $docs | Where-Object {$RulesNotSupportedInNetstandard2 -notcontains $_} + $readmeRules = $readmeRules | Where-Object {$RulesNotSupportedInNetstandard2 -notcontains $_} + } + elseif ($PSVersionTable.PSVersion.Major -eq 4) { + $docs = $docs | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'} + $readmeRules = $readmeRules | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'} + } + + $rulesDocsDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $docs -SyncWindow 25 $rulesReadmeDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $readmeRules -SyncWindow 25 } From 5753492620827e2b888ffc765e8bc5026c1b8134 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 19 May 2018 09:15:19 +0100 Subject: [PATCH 09/12] Remove leftovers from deprecated rules AvoidUsingFilePath, AvoidUninitializedVariable and AvoidTrapStatement in code and documentation. Fix markdown in PowerShellBestPractices.md and tidy up --- Engine/Settings/PSGallery.psd1 | 1 - Engine/Settings/ScriptSecurity.psd1 | 3 +- PowerShellBestPractices.md | 265 +++++++++--------- Rules/Strings.Designer.cs | 112 +------- Rules/Strings.resx | 36 --- .../Documentation/RuleDocumentation.tests.ps1 | 4 +- Tests/Engine/Profile.ps1 | 6 +- Tests/Engine/WrongProfile.ps1 | 3 +- .../AvoidGlobalOrUnitializedVars.tests.ps1 | 83 ------ Tests/Rules/AvoidGlobalVars.tests.ps1 | 42 +++ 10 files changed, 190 insertions(+), 365 deletions(-) delete mode 100644 Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 create mode 100644 Tests/Rules/AvoidGlobalVars.tests.ps1 diff --git a/Engine/Settings/PSGallery.psd1 b/Engine/Settings/PSGallery.psd1 index 8064ba84e..8152ea7c7 100644 --- a/Engine/Settings/PSGallery.psd1 +++ b/Engine/Settings/PSGallery.psd1 @@ -21,7 +21,6 @@ 'PSAvoidUsingConvertToSecureStringWithPlainText', 'PSUsePSCredentialType', 'PSAvoidUsingUserNameAndPasswordParams', - 'PSAvoidUsingFilePath', 'PSDSC*' ) } diff --git a/Engine/Settings/ScriptSecurity.psd1 b/Engine/Settings/ScriptSecurity.psd1 index 3be041013..5e71037c2 100644 --- a/Engine/Settings/ScriptSecurity.psd1 +++ b/Engine/Settings/ScriptSecurity.psd1 @@ -3,6 +3,5 @@ 'PSAvoidUsingComputerNameHardcoded', 'PSAvoidUsingConvertToSecureStringWithPlainText', 'PSUsePSCredentialType', - 'PSAvoidUsingUserNameAndPasswordParams', - 'PSAvoidUsingFilePath') + 'PSAvoidUsingUserNameAndPasswordParams') } \ No newline at end of file diff --git a/PowerShellBestPractices.md b/PowerShellBestPractices.md index 81bc3e00c..717810394 100644 --- a/PowerShellBestPractices.md +++ b/PowerShellBestPractices.md @@ -1,129 +1,144 @@ -#PowerShell Best Practices - -The following guidelines come from a combined effort from both the PowerShell team and the community. We will use this guideline to define rules for PSScriptAnalyzer. Please feel free to propose additional guidelines and rules for PSScriptAnalyzer. -**Note: The hyperlink next to each guidelines will redirect to documentation page for the rule that is already implemented. - -##Cmdlet Design Rules -###Severity: Error - -###Severity: Warning - - Use Only Approved Verbs [UseApprovedVerbs](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseApprovedVerbs.md) - - Cmdlets Names: Characters that cannot be Used [AvoidReservedCharInCmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidReservedCharInCmdlet.md) - - Parameter Names that cannot be Used [AvoidReservedParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidReservedParams.md) - - Support Confirmation Requests [UseShouldProcessCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessCorrectly.md) and [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) - - Nouns should be singular [UseSingularNouns](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseSingularNouns.md) - - Module Manifest Fields [MissingModuleManifestField](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/MissingModuleManifestField.md) - - Version - - Author - - Description - - LicenseUri (for PowerShell Gallery) - - Must call ShouldProcess when ShouldProcess attribute is present and vice versa.[UseShouldProcessCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessCorrectly.md) - - Switch parameters should not default to true  [AvoidDefaultTrueValueSwtichParameter](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidDefaultTrueValueSwitchParameter.md) - -###Severity: Information - -###Severity: TBD - - Support Force Parameter for Interactive Session - - If your cmdlet is used interactively, always provide a Force parameter to override the interactive actions, such as prompts or reading lines of input). This is important because it allows your cmdlet to be used in non-interactive scripts and hosts. The following methods can be implemented by an interactive host. - - Document Output Objects - - Module must be loadable - - No syntax errors - - Unresolved dependencies are an error - - Derive from the Cmdlet or PSCmdlet Classes - - Specify the Cmdlet Attribute - - Override an Input Processing Method - - Specify the OutputType Attribute - - Write Single Records to the Pipeline - - Make Cmdlets Case-Insensitive and Case-Preserving - -##Script Functions -###Severity: Error - -###Severity: Warning - - Avoid using alias [AvoidAlias](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidAlias.md) - - Avoid using deprecated WMI cmdlets [AvoidUsingWMICmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWMICmdlet.md) - - Empty catch block should not be used [AvoidEmptyCatchBlock](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidEmptyCatchBlock.md) - - Invoke existing cmdlet with correct parameters [UseCmdletCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseCmdletCorrectly.md) - - Cmdlets should have ShouldProcess/ShouldContinue and Force param if certain system-modding verbs are present (Update, Set, Remove, New)[UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) - - Positional parameters should be avoided [AvoidUsingPositionalParameters](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPositionalParameters.md) - - Non-global variables must be initialized. Those that are supposed to be global and not initialized must have “global:” (includes for loop initializations)[AvoidUninitializedVariable](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUninitializedVariable.md) - - Global variables should be avoided. [AvoidGlobalVars](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidGlobalVars.md) - - Declared variables must be used in more than just their assignment. [UseDeclaredVarsMoreThanAssignments](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md) - - No trap statments should be used [AvoidTrapStatement](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidTrapStatement.md) - - No Invoke-Expression [AvoidUsingInvokeExpression](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingInvokeExpression.md) - -###Severity: Information - -###Severity: TBD - - Clear-Host should not be used - - File paths should not be used (UNC) - - Error Handling - - Use -ErrorAction Stop when calling cmdlets - - Use $ErrorActionPreference = 'Stop'/' Continue' when calling non-cmdlets - - Avoid using flags to handle errors - - Avoid using $? - - Avoid testing for a null variable as an error condition - - Copy $Error[0] to your own variable - - Avoid using pipelines in scripts - - If a return type is declared, the cmdlet must return that type. If a type is returned, a return type must be declared. - -##Scripting Style -###Severity: Error - -###Severity: Warning - - Don't use write-host unless writing to the host is all you want to do [AvoidUsingWriteHost](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWriteHost.md) - -###Severity: Information - - Write comment-based help [ProvideCommentHelp](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ProvideCommentHelp.md) - - Use write-verbose to give information to someone running your script [ProvideVerboseMessage](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ProvideVerboseMessage.md) -###Severity: TBD - - Provide usage Examples - - Use the Notes section for detail on how the tool work - - Should have help on every exported command (including parameter documentation - - Document the version of PowerShell that script was written for - - Indent your code - - Avoid backticks - - -##Script Security -###Severity: Error - - Password should be secure string [AvoidUsingPlainTextForPassword](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPlainTextForPassword.md)- Should never have both -Username and -Password parameters (should take credentials)[UsePSCredentialType](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UsePSCredentialType.md) - - -ComputerName hardcoded should not be used (information disclosure)[AvoidUsingComputerNameHardcoded](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingComputerNameHardcoded.md) - - ConvertTo-SecureString with plaintext should not be used (information disclosure) [AvoidUsingConvertToSecureStringWithPlainText](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md) - -###Severity: Warning +# PowerShell Best Practices + +The following guidelines come from a combined effort from both the PowerShell team and the community. We will use this guideline to define rules for `PSScriptAnalyzer`. Please feel free to propose additional guidelines and rules for `PSScriptAnalyzer`. +**Note**: The hyperlink next to each guidelines will redirect to documentation page for the rule that is already implemented. + +## Cmdlet Design Rules + +### Severity: Error + +### Severity: Warning + +- Use Only Approved Verbs [UseApprovedVerbs](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseApprovedVerbs.md) +- Cmdlets Names: Characters that cannot be Used [AvoidReservedCharInCmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedCmdletChar.md) +- Parameter Names that cannot be Used [AvoidReservedParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedParams.md) +- Support Confirmation Requests [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) and [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) +- Must call ShouldProcess when ShouldProcess attribute is present and vice versa.[UseShouldProcess](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ShouldProcess.md) +- Nouns should be singular [UseSingularNouns](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseSingularNouns.md) +- Module Manifest Fields [MissingModuleManifestField](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/MissingModuleManifestField.md) + - Version + - Author + - Description + - LicenseUri (for PowerShell Gallery) +- Switch parameters should not default to true  [AvoidDefaultValueSwitchParameter](https://github.com/PowetrShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidDefaultValueSwitchParameter.md) + +### Severity: Information + +### Severity: TBD + +- Support Force Parameter for Interactive Session +- If your cmdlet is used interactively, always provide a Force parameter to override the interactive actions, such as prompts or reading lines of input). This is important because it allows your cmdlet to be used in non-interactive scripts and hosts. The following methods can be implemented by an interactive host. +- Document Output Objects +- Module must be loadable +- No syntax errors +- Unresolved dependencies are an error +- Derive from the Cmdlet or PSCmdlet Classes +- Specify the Cmdlet Attribute +- Override an Input Processing Method +- Specify the OutputType Attribute +- Write Single Records to the Pipeline +- Make Cmdlets Case-Insensitive and Case-Preserving + +## Script Functions + +### Severity: Error + +### Severity: Warning + +- Avoid using alias [AvoidUsingCmdletAliases](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingCmdletAliases.md) +- Avoid using deprecated WMI cmdlets [AvoidUsingWMICmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWMICmdlet.md) +- Empty catch block should not be used [AvoidUsingEmptyCatchBlock](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingEmptyCatchBlock.md) +- Invoke existing cmdlet with correct parameters [UseCmdletCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseCmdletCorrectly.md) +- Cmdlets should have ShouldProcess/ShouldContinue and Force param if certain system-modding verbs are present (Update, Set, Remove, New): [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) +- Positional parameters should be avoided [AvoidUsingPositionalParameters](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPositionalParameters.md) +- Global variables should be avoided. [AvoidGlobalVars](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidGlobalVars.md) +- Declared variables must be used in more than just their assignment. [UseDeclaredVarsMoreThanAssignments](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md) +- No Invoke-Expression [AvoidUsingInvokeExpression](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingInvokeExpression.md) + +### Severity: Information + +### Severity: TBD + +- `Clear-Host` should not be used +- File paths should not be used (UNC) +- Error Handling + - Use `-ErrorAction Stop` when calling cmdlets + - Use $ErrorActionPreference = 'Stop'/' Continue' when calling non-cmdlets + - Avoid using flags to handle errors + - Avoid using `$?` + - Avoid testing for a null variable as an error condition + - Copy `$Error[0]` to your own variable +- Avoid using pipelines in scripts +- If a return type is declared, the cmdlet must return that type. If a type is returned, a return type must be declared. + +## Scripting Style + +### Severity: Error + +### Severity: Warning + +- Don't use `Write-Host` unless writing to the host is all you want to do [AvoidUsingWriteHost](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWriteHost.md) + +### Severity: Information + +- Write comment-based help [ProvideCommentHelp](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ProvideCommentHelp.md) + +### Severity: TBD + +- Provide usage Examples +- Use the Notes section for detail on how the tool work +- Should have help on every exported command (including parameter documentation +- Document the version of PowerShell that script was written for +- Indent your code +- Avoid backticks + +## Script Security + +### Severity: Error + +- Password should be secure string [AvoidUsingPlainTextForPassword](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPlainTextForPassword.md)- Should never have both -Username and -Password parameters (should take credentials): [UsePSCredentialType](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UsePSCredentialType.md) +- `-ComputerName` Parameter argument hardcoded should not be used (information disclosure): [AvoidUsingComputerNameHardcoded](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingComputerNameHardcoded.md) +- ConvertTo-SecureString with plaintext should not be used (information disclosure): [AvoidUsingConvertToSecureStringWithPlainText](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md) + +### Severity: Warning + - Password = 'string' should not be used. (information disclosure) [AvoidUsingUsernameAndPasswordParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md) -- Internal URLs should not be used (information disclosure)[AvoidUsingFilePath](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingFilePath.md) - -###Severity: Information - -###Severity: TBD - - APIKey and Credentials variables that are initialized (information disclosure) - -##DSC Related Rules -###Severity: Error - - Use standard DSC methods [UseStandardDSCFunctionsInResource](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseStandardDSC FunctionsInResource.md) - - Use identical mandatory parameters for all DSC methods [UseIdenticalMandatoryParametersDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalMandatoryParametersDSC.md) - - Use identical parameters for Set and Test DSC methods [UseIdenticalParametersDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalParametersDSC.md) - -###Severity: Warning - -###Severity: Information - - All of the following three rule are grouped by: [ReturnCorrectTypeDSCFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReturnCorrectTypeDSCFunctions.md) - - Avoid return any object from a Set-TargetResource or Set (Class Based) function - - Returning a Boolean object from a Test-TargetResource or Test (Class Based) function - - Returning an object from a Get-TargetResource or Get (Class Based) function - - DSC resources should have DSC tests [DSCTestsPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscTestsPresent.md) - - DSC resources should have DSC examples [DSCExamplesPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscExamplesPresent.md) - -###Severity: TBD - - For PowerShell V4: Resource module contains .psd1 file and schema.mof for every resource - - MOF has description for each element [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/131) - - Resource module must contain .psd1 file (always) and schema.mof (for non-class resource). [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/116) - - Use ShouldProcess for a Set DSC method - - Resource module contains DscResources folder which contains the resources [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/130) - -###Reference: + +### Severity: Information + +### Severity: TBD + +- APIKey and Credentials variables that are initialized (information disclosure) + +## DSC Related Rules + +### Severity: Error + +- Use standard DSC methods [StandardDSCFunctionsInResource](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/StandardDSCFunctionsInResource.md) +- Use identical mandatory parameters for all DSC methods [UseIdenticalMandatoryParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md) +- Use identical parameters for Set and Test DSC methods [UseIdenticalParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalParametersForDSC.md) + +### Severity: Warning + +### Severity: Information + +- All of the following three rule are grouped by: [ReturnCorrectTypesForDSCFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReturnCorrectTypesForDSCFunctions.md) +- Avoid return any object from a `Set-TargetResource` or Set (Class Based) function +- Returning a Boolean object from a `Test-TargetResource` or Test (Class Based) function +- Returning an object from a `Get-TargetResource` or Get (Class Based) function +- DSC resources should have DSC tests [DSCTestsPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscTestsPresent.md) +- DSC resources should have DSC examples [DSCExamplesPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscExamplesPresent.md) + +### Severity: TBD + +- For PowerShell V4: Resource module contains `.psd1` file and `schema.mof` for every resource +- MOF has description for each element [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/131) +- Resource module must contain .psd1 file (always) and schema.mof (for non-class resource). [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/116) +- Use ShouldProcess for a Set DSC method +- Resource module contains DscResources folder which contains the resources [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/130) + +### Reference + * Cmdlet Development Guidelines from MSDN site (Cmdlet Development Guidelines): https://msdn.microsoft.com/en-us/library/ms714657(v=vs.85).aspx * The Community Book of PowerShell Practices (Compiled by Don Jones and Matt Penny and the Windows PowerShell Community): https://powershell.org/community-book-of-powershell-practices/ * PowerShell DSC Resource Design and Testing Checklist: https://blogs.msdn.com/b/powershell/archive/2014/11/18/powershell-dsc-resource-design-and-testing-checklist.aspx diff --git a/Rules/Strings.Designer.cs b/Rules/Strings.Designer.cs index 45439a104..ba1d61a4d 100644 --- a/Rules/Strings.Designer.cs +++ b/Rules/Strings.Designer.cs @@ -537,79 +537,7 @@ internal static string AvoidTrailingWhitespaceName { return ResourceManager.GetString("AvoidTrailingWhitespaceName", resourceCulture); } } - - /// - /// Looks up a localized string similar to No traps in the script.. - /// - internal static string AvoidTrapStatementCommonName { - get { - return ResourceManager.GetString("AvoidTrapStatementCommonName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Avoid using Traps in the script.. - /// - internal static string AvoidTrapStatementDescription { - get { - return ResourceManager.GetString("AvoidTrapStatementDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Trap found.. - /// - internal static string AvoidTrapStatementError { - get { - return ResourceManager.GetString("AvoidTrapStatementError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AvoidTrapStatement. - /// - internal static string AvoidTrapStatementName { - get { - return ResourceManager.GetString("AvoidTrapStatementName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Initializing non-global variables. - /// - internal static string AvoidUninitializedVariableCommonName { - get { - return ResourceManager.GetString("AvoidUninitializedVariableCommonName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables.. - /// - internal static string AvoidUninitializedVariableDescription { - get { - return ResourceManager.GetString("AvoidUninitializedVariableDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Variable '{0}' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables.. - /// - internal static string AvoidUninitializedVariableError { - get { - return ResourceManager.GetString("AvoidUninitializedVariableError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AvoidUninitializedVariable. - /// - internal static string AvoidUninitializedVariableName { - get { - return ResourceManager.GetString("AvoidUninitializedVariableName", resourceCulture); - } - } - + /// /// Looks up a localized string similar to Module Must Be Loadable. /// @@ -879,43 +807,7 @@ internal static string AvoidUsingEmptyCatchBlockName { return ResourceManager.GetString("AvoidUsingEmptyCatchBlockName", resourceCulture); } } - - /// - /// Looks up a localized string similar to Avoid Using File Path. - /// - internal static string AvoidUsingFilePathCommonName { - get { - return ResourceManager.GetString("AvoidUsingFilePathCommonName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to If a rooted file path is used in a script that is published online, this may expose information about your computer. Furthermore, the file path may not work on other computer when they try to use the script.. - /// - internal static string AvoidUsingFilePathDescription { - get { - return ResourceManager.GetString("AvoidUsingFilePathDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The file path '{0}' of '{1}' is rooted. This should be avoided if '{1}' is published online.. - /// - internal static string AvoidUsingFilePathError { - get { - return ResourceManager.GetString("AvoidUsingFilePathError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AvoidUsingFilePath. - /// - internal static string AvoidUsingFilePathName { - get { - return ResourceManager.GetString("AvoidUsingFilePathName", resourceCulture); - } - } - + /// /// Looks up a localized string similar to Avoid Using Internal URLs. /// diff --git a/Rules/Strings.resx b/Rules/Strings.resx index facd68c2e..d4ebf259c 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -168,12 +168,6 @@ Extra Variables - - Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables. - - - Initializing non-global variables - Checks that global variables are not used. Global variables are strongly discouraged as they can cause errors across different systems. @@ -183,15 +177,6 @@ No Global Variables - - Avoid using Traps in the script. - - - Trap found. - - - No traps in the script. - Checks that $null is on the left side of any equaltiy comparisons (eq, ne, ceq, cne, ieq, ine). When there is an array on the left side of a null equality comparison, PowerShell will check for a $null IN the array rather than if the array is null. If the two sides of the comaprision are switched this is fixed. Therefore, $null should always be on the left side of equality comparisons just in case. @@ -300,15 +285,6 @@ Module Must Be Loadable - - If a rooted file path is used in a script that is published online, this may expose information about your computer. Furthermore, the file path may not work on other computer when they try to use the script. - - - The file path '{0}' of '{1}' is rooted. This should be avoided if '{1}' is published online. - - - Avoid Using File Path - Error Message is Null. @@ -390,12 +366,6 @@ AvoidShouldContinueWithoutForce - - AvoidTrapStatement - - - AvoidUninitializedVariable - AvoidUnloadableModule @@ -408,9 +378,6 @@ AvoidUsingEmptyCatchBlock - - AvoidUsingFilePath - AvoidUsingInvokeExpression @@ -609,9 +576,6 @@ Missing '{0}' function. DSC Class must implement Get, Set and Test functions. - - Variable '{0}' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables. - Use identical mandatory parameters for DSC Get/Test/Set TargetResource functions diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 index e312ca0ad..8306c25ee 100644 --- a/Tests/Documentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -24,11 +24,11 @@ Describe "Validate rule documentation files" { { $RulesNotSupportedInNetstandard2 = @("PSUseSingularNouns") $docs = $docs | Where-Object {$RulesNotSupportedInNetstandard2 -notcontains $_} - $readmeRules = $readmeRules | Where-Object {$RulesNotSupportedInNetstandard2 -notcontains $_} + $readmeRules = $readmeRules | Where-Object { $RulesNotSupportedInNetstandard2 -notcontains $_ } } elseif ($PSVersionTable.PSVersion.Major -eq 4) { $docs = $docs | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'} - $readmeRules = $readmeRules | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'} + $readmeRules = $readmeRules | Where-Object { $_ -notmatch '^PSAvoidGlobalAliases$' } } $rulesDocsDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $docs -SyncWindow 25 diff --git a/Tests/Engine/Profile.ps1 b/Tests/Engine/Profile.ps1 index 8bc4bc7e2..c18253647 100644 --- a/Tests/Engine/Profile.ps1 +++ b/Tests/Engine/Profile.ps1 @@ -2,8 +2,6 @@ Severity='Warning' IncludeRules=@('PSAvoidUsingCmdletAliases', 'PSAvoidUsingPositionalParameters', - 'PSAvoidUsingInternalURLs' - 'PSAvoidUninitializedVariable') - ExcludeRules=@('PSAvoidUsingCmdletAliases' - 'PSAvoidUninitializedVariable') + 'PSAvoidUsingInternalURLs') + ExcludeRules=@('PSAvoidUsingCmdletAliases') } \ No newline at end of file diff --git a/Tests/Engine/WrongProfile.ps1 b/Tests/Engine/WrongProfile.ps1 index b11fbd07b..035e1fac3 100644 --- a/Tests/Engine/WrongProfile.ps1 +++ b/Tests/Engine/WrongProfile.ps1 @@ -2,8 +2,7 @@ Severity='Warning' IncludeRules=@('PSAvoidUsingCmdletAliases', 'PSAvoidUsingPositionalParameters', - 'PSAvoidUsingInternalURLs' - 'PSAvoidUninitializedVariable') + 'PSAvoidUsingInternalURLs') ExcludeRules=@(1) Exclude=@('blah') } \ No newline at end of file diff --git a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 b/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 deleted file mode 100644 index d1caa053c..000000000 --- a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 +++ /dev/null @@ -1,83 +0,0 @@ -$globalMessage = "Found global variable 'Global:1'." -$globalName = "PSAvoidGlobalVars" - -# PSAvoidUninitializedVariable rule has been deprecated -# $nonInitializedName = "PSAvoidUninitializedVariable" - -$nonInitializedMessage = "Variable 'globalVars' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables." -$directory = Split-Path -Parent $MyInvocation.MyCommand.Path -$violations = Invoke-ScriptAnalyzer $directory\AvoidGlobalOrUnitializedVars.ps1 - -# PSAvoidUninitializedVariable rule has been deprecated -# $dscResourceViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $nonInitializedName} - -$globalViolations = $violations | Where-Object {$_.RuleName -eq $globalName} - -# PSAvoidUninitializedVariable rule has been deprecated -# $nonInitializedViolations = $violations | Where-Object {$_.RuleName -eq $nonInitializedName} - -$noViolations = Invoke-ScriptAnalyzer $directory\AvoidGlobalOrUnitializedVarsNoViolations.ps1 -$noGlobalViolations = $noViolations | Where-Object {$_.RuleName -eq $globalName} - -# PSAvoidUninitializedVariable rule has been deprecated -# $noUninitializedViolations = $noViolations | Where-Object {$_.RuleName -eq $nonInitializedName} - -Describe "AvoidGlobalVars" { - Context "When there are violations" { - It "has 1 avoid using global variable violation" { - $globalViolations.Count | Should -Be 1 - } - - <# - # PSAvoidUninitializedVariable rule has been deprecated - It "has 4 violations for dsc resources (not counting the variables in parameters)" { - $dscResourceViolations.Count | Should -Be 4 - } - #> - - - It "has the correct description message" { - $globalViolations[0].Message | Should -Match $globalMessage - } - } - - Context "When there are no violations" { - It "returns no violations" { - $noGlobalViolations.Count | Should -Be 0 - } - } - - Context "When a script contains global:lastexitcode" { - It "returns no violation" { - $def = @' -if ($global:lastexitcode -ne 0) -{ - exit -} -'@ - $local:violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -IncludeRule $globalName - $local:violations.Count | Should -Be 0 - } - } -} - -<# -# PSAvoidUninitializedVariable rule has been deprecated - Hence not a valid test case -Describe "AvoidUnitializedVars" { - Context "When there are violations" { - It "has 5 avoid using unitialized variable violations" { - $nonInitializedViolations.Count | Should -Be 5 - } - - It "has the correct description message" { - $nonInitializedViolations[0].Message | Should -Match $nonInitializedMessage - } - } - - Context "When there are no violations" { - It "returns no violations" { - $noUninitializedViolations.Count | Should -Be 0 - } - } -} -#> diff --git a/Tests/Rules/AvoidGlobalVars.tests.ps1 b/Tests/Rules/AvoidGlobalVars.tests.ps1 new file mode 100644 index 000000000..8a4611e52 --- /dev/null +++ b/Tests/Rules/AvoidGlobalVars.tests.ps1 @@ -0,0 +1,42 @@ +$globalMessage = "Found global variable 'Global:1'." +$globalName = "PSAvoidGlobalVars" + +$nonInitializedMessage = "Variable 'globalVars' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables." +$directory = Split-Path -Parent $MyInvocation.MyCommand.Path +$violations = Invoke-ScriptAnalyzer $directory\AvoidGlobalOrUnitializedVars.ps1 + +$globalViolations = $violations | Where-Object {$_.RuleName -eq $globalName} + +$noViolations = Invoke-ScriptAnalyzer $directory\AvoidGlobalOrUnitializedVarsNoViolations.ps1 +$noGlobalViolations = $noViolations | Where-Object {$_.RuleName -eq $globalName} + +Describe "AvoidGlobalVars" { + Context "When there are violations" { + It "has 1 avoid using global variable violation" { + $globalViolations.Count | Should -Be 1 + } + + It "has the correct description message" { + $globalViolations[0].Message | Should -Match $globalMessage + } + } + + Context "When there are no violations" { + It "returns no violations" { + $noGlobalViolations.Count | Should -Be 0 + } + } + + Context "When a script contains global:lastexitcode" { + It "returns no violation" { + $def = @' +if ($global:lastexitcode -ne 0) +{ + exit +} +'@ + $local:violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -IncludeRule $globalName + $local:violations.Count | Should -Be 0 + } + } +} From 58a8aee08bbbf1d03645706c68c573711fddb2aa Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 19 May 2018 09:20:07 +0100 Subject: [PATCH 10/12] added remarks about rules not being available in certain powershell versions --- RuleDocumentation/AvoidGlobalAliases.md | 5 +++-- RuleDocumentation/UseSingularNouns.md | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/RuleDocumentation/AvoidGlobalAliases.md b/RuleDocumentation/AvoidGlobalAliases.md index d0c02e1aa..dd4bd3807 100644 --- a/RuleDocumentation/AvoidGlobalAliases.md +++ b/RuleDocumentation/AvoidGlobalAliases.md @@ -4,11 +4,12 @@ ## 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```. +**NOTE** This rule is not available in PowerShell version 3 and 4 due to the `StaticParameterBinder.BindCommand` API that the rule uses internally. + ## How Use other scope modifiers for new aliases. diff --git a/RuleDocumentation/UseSingularNouns.md b/RuleDocumentation/UseSingularNouns.md index c123bdf43..1966cd2a3 100644 --- a/RuleDocumentation/UseSingularNouns.md +++ b/RuleDocumentation/UseSingularNouns.md @@ -6,6 +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. + ## How Change plurals to singular. From 48f6be37b44ec2a743e30ad0781fa69d380b128c Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 19 May 2018 10:11:53 -0600 Subject: [PATCH 11/12] Add superscript/footnote on rules not available everywhere --- RuleDocumentation/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md index efd139b7d..a8ac87cf1 100644 --- a/RuleDocumentation/README.md +++ b/RuleDocumentation/README.md @@ -8,7 +8,7 @@ |[AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md) | Warning | | |[AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | | |[AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | | -|[AvoidGlobalAliases](./AvoidGlobalAliases.md) | Warning | | +|[AvoidGlobalAliases*](./AvoidGlobalAliases.md) | Warning | | |[AvoidGlobalFunctions](./AvoidGlobalFunctions.md) | Warning | | |[AvoidGlobalVars](./AvoidGlobalVars.md) | Warning | | |[AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning | | @@ -50,7 +50,7 @@ |[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | | |[UsePSCredentialType](./UsePSCredentialType.md) | Warning | | |[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | | -|[UseSingularNouns](./UseSingularNouns.md) | Warning | | +|[UseSingularNouns*](./UseSingularNouns.md) | Warning | | |[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | | |[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | | |[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning | Yes | @@ -59,3 +59,5 @@ |[UseConsistentIndentation](./UseConsistentIndentation.md) | Warning | Yes | |[UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning | Yes | |[UseUTF8EncodingForHelpFile](./UseUTF8EncodingForHelpFile.md) | Warning | | + +* Rule is not available on all PowerShell versions, editions and/or OS platforms. See the rule's documentation for details. From 796865389a3373ce4443438d05be60f7d2b04e5b Mon Sep 17 00:00:00 2001 From: Keith Hill Date: Sat, 19 May 2018 10:23:24 -0600 Subject: [PATCH 12/12] Update test to strip off the optional superscript markdown --- Tests/Documentation/RuleDocumentation.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 index 8306c25ee..ca41f4819 100644 --- a/Tests/Documentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -13,7 +13,7 @@ Describe "Validate rule documentation files" { $readmeLinks = @{} $readmeRules = Get-Content -LiteralPath $ruleDocDirectory/README.md | Foreach-Object { if ($_ -match '^\s*\|\s*\[([^]]+)\]\(([^)]+)\)\s*\|') { - $ruleName = $matches[1] + $ruleName = $matches[1] -replace '.$', '' $readmeLinks["$ruleName"] = $matches[2] "PS${ruleName}" }} |