From 578fa16be780b6b7a013bd5521b82cd350c833d3 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:27:37 +0100 Subject: [PATCH 01/29] Refactor skip logic in PSScriptAnalyzer tests for improved clarity and maintainability --- .../PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 6ff16bb..0f6dd19 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -21,13 +21,28 @@ BeforeDiscovery { $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique foreach ($ruleObject in $ruleObjects) { + $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { + $true + } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { + $skip = $true + } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { + $skip = $true + } elseif ($settings.SourceType -and $ruleObject.SourceType -notin $settings.SourceType) { + $skip = $true + } elseif ($settings.SourceName -and $ruleObject.SourceName -notin $settings.SourceName) { + $skip = $true + } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and $settings.Rules[$ruleObject.RuleName].Enabled -eq $false) { + $skip = $true + } else { + $skip = $false + } $rules.Add( [ordered]@{ RuleName = $ruleObject.RuleName CommonName = $ruleObject.CommonName Severity = $ruleObject.Severity Description = $ruleObject.Description - Skip = $ruleObject.RuleName -in $settings.ExcludeRules + Skip = $skip <# RuleName : PSDSCUseVerboseMessageInDSCResource CommonName : Use verbose message in DSC resource From 5c5c7f7bc518aef76e1be910726c4f39c0ec1c0e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:28:17 +0100 Subject: [PATCH 02/29] Refactor condition for skipping rules in PSScriptAnalyzer tests for improved readability --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 0f6dd19..e334e02 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -31,7 +31,7 @@ BeforeDiscovery { $skip = $true } elseif ($settings.SourceName -and $ruleObject.SourceName -notin $settings.SourceName) { $skip = $true - } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and $settings.Rules[$ruleObject.RuleName].Enabled -eq $false) { + } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { $skip = $true } else { $skip = $false From bda02e54a7426c2d1513ce458d8b96acec7c1309 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:39:39 +0100 Subject: [PATCH 03/29] Add custom settings for PSScriptAnalyzer rules and configurations --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 72 ++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/srcTestRepo/tests/Custom.Settings.psd1 diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 new file mode 100644 index 0000000..6364c1e --- /dev/null +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -0,0 +1,72 @@ +@{ + Rules = @{ + PSAlignAssignmentStatement = @{ + Enable = $true + CheckHashtable = $true + } + PSAvoidLongLines = @{ + Enable = $false + MaximumLineLength = 150 + } + PSAvoidSemicolonsAsLineTerminators = @{ + Enable = $true + } + PSPlaceCloseBrace = @{ + Enable = $true + NewLineAfter = $false + IgnoreOneLineBlock = $true + NoEmptyLineBefore = $false + } + PSPlaceOpenBrace = @{ + Enable = $true + OnSameLine = $true + NewLineAfter = $true + IgnoreOneLineBlock = $true + } + PSProvideCommentHelp = @{ + Enable = $true + ExportedOnly = $false + BlockComment = $true + VSCodeSnippetCorrection = $false + Placement = 'begin' + } + PSUseConsistentIndentation = @{ + Enable = $true + IndentationSize = 4 + PipelineIndentation = 'IncreaseIndentationForFirstPipeline' + Kind = 'space' + } + PSUseConsistentWhitespace = @{ + Enable = $true + CheckInnerBrace = $true + CheckOpenBrace = $true + CheckOpenParen = $true + CheckOperator = $true + CheckPipe = $true + CheckPipeForRedundantWhitespace = $true + CheckSeparator = $true + CheckParameter = $true + IgnoreAssignmentOperatorInsideHashTable = $true + } + } + ExcludeRules = @( + 'PSUseConsistentWhitespace' + ) + IncludedRules = @( + 'PSAvoidSemicolonsAsLineTerminators' + 'PSPlaceCloseBrace' + 'PSPlaceOpenBrace' + 'PSProvideCommentHelp' + 'PSUseConsistentIndentation' + ) + Severity = @( + 'Error' + 'Warning' + ) + SourceType = @( + 'Builtin' + ) + SourceName = @( + 'PS' + ) +} From fed0fcca16d0eb8e2e051eb496ab00f243eb792e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:42:27 +0100 Subject: [PATCH 04/29] Add custom action test configuration and remove unused settings file path --- .github/workflows/Action-Test-Src-Default.yml | 8 ++++++++ .github/workflows/Action-Test-outputs.yml | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Action-Test-Src-Default.yml b/.github/workflows/Action-Test-Src-Default.yml index 7896cc0..bd9aca9 100644 --- a/.github/workflows/Action-Test-Src-Default.yml +++ b/.github/workflows/Action-Test-Src-Default.yml @@ -21,3 +21,11 @@ jobs: TestType: Src-Default Path: tests/srcTestRepo/src Settings: SourceCode + + ActionTestCustom: + uses: ./.github/workflows/ActionTestWorkflow.yml + with: + TestType: Src-Default-Custom + Path: tests/srcTestRepo/src + Settings: Custom + SettingsFilePath: tests/srcTestRepo/tests/Custom.Settings.psd1 diff --git a/.github/workflows/Action-Test-outputs.yml b/.github/workflows/Action-Test-outputs.yml index c318e4c..38094ad 100644 --- a/.github/workflows/Action-Test-outputs.yml +++ b/.github/workflows/Action-Test-outputs.yml @@ -21,4 +21,3 @@ jobs: TestType: outputs Path: tests/outputTestRepo/outputs/modules/PSModuleTest Settings: Module - SettingsFilePath: From 32a63aca9fdc685600d99cdbbd10cf82e4944a4c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:43:26 +0100 Subject: [PATCH 05/29] Add custom action test configuration for Src-Default-Custom --- .../Action-Test-Src-Default-Custom.yml | 24 +++++++++++++++++++ .github/workflows/Action-Test-Src-Default.yml | 8 ------- 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/Action-Test-Src-Default-Custom.yml diff --git a/.github/workflows/Action-Test-Src-Default-Custom.yml b/.github/workflows/Action-Test-Src-Default-Custom.yml new file mode 100644 index 0000000..e89fa3b --- /dev/null +++ b/.github/workflows/Action-Test-Src-Default-Custom.yml @@ -0,0 +1,24 @@ +name: Action-Test [Src-Default-Custom] + +run-name: "Action-Test [Src-Default-Custom] - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}" + +on: + workflow_dispatch: + pull_request: + schedule: + - cron: '0 0 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + ActionTestCustom: + uses: ./.github/workflows/ActionTestWorkflow.yml + with: + TestType: Src-Default-Custom + Path: tests/srcTestRepo/src + Settings: Custom + SettingsFilePath: tests/srcTestRepo/tests/Custom.Settings.psd1 diff --git a/.github/workflows/Action-Test-Src-Default.yml b/.github/workflows/Action-Test-Src-Default.yml index bd9aca9..7896cc0 100644 --- a/.github/workflows/Action-Test-Src-Default.yml +++ b/.github/workflows/Action-Test-Src-Default.yml @@ -21,11 +21,3 @@ jobs: TestType: Src-Default Path: tests/srcTestRepo/src Settings: SourceCode - - ActionTestCustom: - uses: ./.github/workflows/ActionTestWorkflow.yml - with: - TestType: Src-Default-Custom - Path: tests/srcTestRepo/src - Settings: Custom - SettingsFilePath: tests/srcTestRepo/tests/Custom.Settings.psd1 From 573c7a6460c982df4cac283c51e7ecb84c2f2c63 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:47:11 +0100 Subject: [PATCH 06/29] Refactor PSScriptAnalyzer tests to simplify skip logic and update custom settings structure --- .../PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 5 +---- tests/srcTestRepo/tests/Custom.Settings.psd1 | 15 +++++---------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index e334e02..f03c174 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -27,15 +27,12 @@ BeforeDiscovery { $skip = $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { $skip = $true - } elseif ($settings.SourceType -and $ruleObject.SourceType -notin $settings.SourceType) { - $skip = $true - } elseif ($settings.SourceName -and $ruleObject.SourceName -notin $settings.SourceName) { - $skip = $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { $skip = $true } else { $skip = $false } + $rules.Add( [ordered]@{ RuleName = $ruleObject.RuleName diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 6364c1e..9187e25 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -1,5 +1,5 @@ @{ - Rules = @{ + Rules = @{ PSAlignAssignmentStatement = @{ Enable = $true CheckHashtable = $true @@ -49,24 +49,19 @@ IgnoreAssignmentOperatorInsideHashTable = $true } } - ExcludeRules = @( + ExcludeRules = @( 'PSUseConsistentWhitespace' ) - IncludedRules = @( + IncludeRules = @( 'PSAvoidSemicolonsAsLineTerminators' 'PSPlaceCloseBrace' 'PSPlaceOpenBrace' 'PSProvideCommentHelp' 'PSUseConsistentIndentation' ) - Severity = @( + IncludeDefaultRules = $true + Severity = @( 'Error' 'Warning' ) - SourceType = @( - 'Builtin' - ) - SourceName = @( - 'PS' - ) } From c01d8555fa947e06a2494826903917abac69b240 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 13:56:08 +0100 Subject: [PATCH 07/29] Update Custom.Settings.psd1 to disable default rules inclusion --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 9187e25..18400ba 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -59,7 +59,7 @@ 'PSProvideCommentHelp' 'PSUseConsistentIndentation' ) - IncludeDefaultRules = $true + IncludeDefaultRules = $false Severity = @( 'Error' 'Warning' From 4ad022da3e47b3afbb8b1d25ab1912905de3ae5d Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 14:18:41 +0100 Subject: [PATCH 08/29] Update documentation and improve rule skipping logic in PSScriptAnalyzer tests --- README.md | 4 +++- .../PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 12 ++++++++---- tests/srcTestRepo/tests/Custom.Settings.psd1 | 1 - 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2bcc8a5..5159c52 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ For detailed documentation on the format of the settings file, see the ## References and Links - [PSScriptAnalyzer Documentation](https://learn.microsoft.com/powershell/module/psscriptanalyzer/) -- [GitHub Super-Linter](https://github.com/github/super-linter) +- [PSScriptAnalyzer Module Overview](https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/overview?view=ps-modules) +- [PSScriptAnalyzer Rules](https://learn.microsoft.com/en-us/powershell/utility-modules/psscriptanalyzer/rules/readme?view=ps-modules) - [PSScriptAnalyzer GitHub Repository](https://github.com/PowerShell/PSScriptAnalyzer) - [Custom Rules in PSScriptAnalyzer](https://docs.microsoft.com/powershell/scripting/developer/hosting/psscriptanalyzer-extensibility) +- [GitHub Super-Linter](https://github.com/github/super-linter) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index f03c174..7249f1c 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -22,15 +22,19 @@ BeforeDiscovery { $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique foreach ($ruleObject in $ruleObjects) { $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { + Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is in the exclude list" -Verbose $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - $skip = $true + Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the include list" -Verbose + $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - $skip = $true + Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the severity list" -Verbose + $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { - $skip = $true + Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose + $true } else { - $skip = $false + $false } $rules.Add( diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 18400ba..7dc2ea9 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -59,7 +59,6 @@ 'PSProvideCommentHelp' 'PSUseConsistentIndentation' ) - IncludeDefaultRules = $false Severity = @( 'Error' 'Warning' From f707bcd74e7a73c6479aec8dd3fd3c2aea6a6f14 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 14:34:26 +0100 Subject: [PATCH 09/29] Refactor PSScriptAnalyzer tests to remove commented-out rule details and streamline settings structure --- .../PSScriptAnalyzer.Tests.ps1 | 10 ------ tests/srcTestRepo/tests/Custom.Settings.psd1 | 8 ++--- tools/records.md | 35 +++++++++++++++++++ 3 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 tools/records.md diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 7249f1c..63a3407 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -44,16 +44,6 @@ BeforeDiscovery { Severity = $ruleObject.Severity Description = $ruleObject.Description Skip = $skip - <# - RuleName : PSDSCUseVerboseMessageInDSCResource - CommonName : Use verbose message in DSC resource - Description : It is a best practice to emit informative, verbose messages in DSC resource functions. - This helps in debugging issues when a DSC configuration is executed. - SourceType : Builtin - SourceName : PSDSC - Severity : Information - ImplementingType : Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseVerboseMessageInDSCResource - #> } ) } diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 7dc2ea9..3734c12 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -1,5 +1,5 @@ @{ - Rules = @{ + Rules = @{ PSAlignAssignmentStatement = @{ Enable = $true CheckHashtable = $true @@ -49,17 +49,17 @@ IgnoreAssignmentOperatorInsideHashTable = $true } } - ExcludeRules = @( + ExcludeRules = @( 'PSUseConsistentWhitespace' ) - IncludeRules = @( + IncludeRules = @( 'PSAvoidSemicolonsAsLineTerminators' 'PSPlaceCloseBrace' 'PSPlaceOpenBrace' 'PSProvideCommentHelp' 'PSUseConsistentIndentation' ) - Severity = @( + Severity = @( 'Error' 'Warning' ) diff --git a/tools/records.md b/tools/records.md new file mode 100644 index 0000000..ced40dd --- /dev/null +++ b/tools/records.md @@ -0,0 +1,35 @@ +## Schema: Get-ScriptAnalyzerRule + +```plaintext + RuleName : PSDSCUseVerboseMessageInDSCResource + CommonName : Use verbose message in DSC resource + Description : It is a best practice to emit informative, verbose messages in DSC resource functions. + This helps in debugging issues when a DSC configuration is executed. + SourceType : Builtin + SourceName : PSDSC + Severity : Information + ImplementingType : Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseVerboseMessageInDSCResource +``` + +## Schema: Invoke-ScriptAnalyzer ERROR record + +```plaintext +Line : 1 +Column : 1 +Message : The member 'ModuleVersion' is not present in the module manifest. This member must exist and be assigned a + version number of the form 'n.n.n.n'. Add the missing member to the file + ' C:\Repos\GitHub\PSModule\Action\Test-PSModule\tests\srcWithManifestTestRepo\src\manifest.psd1'. +Extent : @{ + Author = 'Author' + } +RuleName : PSMissingModuleManifestField +Severity : Warning +ScriptName : manifest.psd1 +ScriptPath : C:\Repos\GitHub\PSModule\Action\Test-PSModule\tests\srcWithManifestTestRepo\src\manifest.psd1 +RuleSuppressionID : +SuggestedCorrections : { + # Version number of this module. + ModuleVersion = '1.0.0.0' + } +IsSuppressed : False +``` From 5300f7bea589971ead8f206351f837a4540f5597 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 14:38:35 +0100 Subject: [PATCH 10/29] Add schema documentation for records used in PSScriptAnalyzer --- tools/records.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/records.md b/tools/records.md index ced40dd..de72969 100644 --- a/tools/records.md +++ b/tools/records.md @@ -1,3 +1,5 @@ +# Schemas for records used in PSScriptAnalyzer + ## Schema: Get-ScriptAnalyzerRule ```plaintext From be00c12ea83fa2387a6093e28f9dafb2c24f9b64 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 15:51:05 +0100 Subject: [PATCH 11/29] Update README and action.yml for improved clarity and versioning --- README.md | 11 +---------- action.yml | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5159c52..9de705c 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,12 @@ # Invoke-ScriptAnalyzer (by PSModule) -This repository contains a GitHub Action that runs PSScriptAnalyzer on your code. +This repository contains a GitHub Action that runs [`PSScriptAnalyzer`](https://github.com/PowerShell/PSScriptAnalyzer) on your code. The action analyzes PowerShell scripts using a hashtable-based settings file to customize rule selection, severity filtering, and custom rule inclusion. > **Note:** This repository includes automated tests that run via Pester to ensure > your settings file is working as expected. -## Action Details - -- **Name:** Invoke-ScriptAnalyzer (by PSModule) -- **Description:** Runs PSScriptAnalyzer on the code. -- **Author:** PSModule -- **Branding:** - Icon: `check-square` - Color: `gray-dark` - ## Inputs | Input | Description | Required | Default | diff --git a/action.yml b/action.yml index 2ef0cde..29b5579 100644 --- a/action.yml +++ b/action.yml @@ -38,7 +38,7 @@ runs: Script: ${{ github.action_path }}/scripts/main.ps1 - name: Invoke-Pester - uses: PSModule/Invoke-Pester@fix + uses: PSModule/Invoke-Pester@v2 id: test env: Settings: ${{ fromJson(steps.paths.outputs.result).Settings }} From 30efe9fb9a34d71370733bb4d2f35523dcdb0344 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 16:14:22 +0100 Subject: [PATCH 12/29] Change severity level from 'Warning' to 'Information' in Custom.Settings.psd1 --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 3734c12..e03d5a0 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -61,6 +61,6 @@ ) Severity = @( 'Error' - 'Warning' + 'Information' ) } From 40439697cd52a5784a94b0f946c2dedd1af76ab4 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 20:11:00 +0100 Subject: [PATCH 13/29] Revert severity level from 'Information' to 'Warning' in Custom.Settings.psd1 and comment out IncludeRules --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index e03d5a0..67a8413 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -52,15 +52,15 @@ ExcludeRules = @( 'PSUseConsistentWhitespace' ) - IncludeRules = @( - 'PSAvoidSemicolonsAsLineTerminators' - 'PSPlaceCloseBrace' - 'PSPlaceOpenBrace' - 'PSProvideCommentHelp' - 'PSUseConsistentIndentation' - ) + # IncludeRules = @( + # 'PSAvoidSemicolonsAsLineTerminators' + # 'PSPlaceCloseBrace' + # 'PSPlaceOpenBrace' + # 'PSProvideCommentHelp' + # 'PSUseConsistentIndentation' + # ) Severity = @( 'Error' - 'Information' + 'Warning' ) } From 38af4808b8dd037ab47eb3830d01bd082c39b2c6 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 20:23:50 +0100 Subject: [PATCH 14/29] Disable PSUseConsistentIndentation rule and update IncludeRules in Custom.Settings.psd1; add test script demonstrating poor PowerShell practices --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 17 +++++++------- tests/srcTestRepo/tests/Test.ps1 | 24 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 tests/srcTestRepo/tests/Test.ps1 diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 67a8413..9dece1c 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -31,7 +31,7 @@ Placement = 'begin' } PSUseConsistentIndentation = @{ - Enable = $true + Enable = $false IndentationSize = 4 PipelineIndentation = 'IncreaseIndentationForFirstPipeline' Kind = 'space' @@ -51,14 +51,15 @@ } ExcludeRules = @( 'PSUseConsistentWhitespace' + 'PSAvoidUsingWriteHost' + ) + IncludeRules = @( + 'PSAvoidSemicolonsAsLineTerminators' + 'PSPlaceCloseBrace' + # 'PSPlaceOpenBrace' + 'PSProvideCommentHelp' + 'PSUseConsistentIndentation' ) - # IncludeRules = @( - # 'PSAvoidSemicolonsAsLineTerminators' - # 'PSPlaceCloseBrace' - # 'PSPlaceOpenBrace' - # 'PSProvideCommentHelp' - # 'PSUseConsistentIndentation' - # ) Severity = @( 'Error' 'Warning' diff --git a/tests/srcTestRepo/tests/Test.ps1 b/tests/srcTestRepo/tests/Test.ps1 new file mode 100644 index 0000000..bb6e101 --- /dev/null +++ b/tests/srcTestRepo/tests/Test.ps1 @@ -0,0 +1,24 @@ +function wreckPSSociety { + # This function is a purposeful exercise in breaking every PowerShell best practice. + # No Verb-Noun naming, no param block, no proper help documentation, + # inconsistent variable naming, and reliance on Write-Host for output. + + if ($args.Count -lt 2) { + Write-Host 'Error: Please supply two arguments.' -ForegroundColor Red + return + } + + # Inconsistent variable names: one lowercase, one uppercase. + $firstVal = $args[0] + $SECONDVAL = $args[1] + + # Arbitrary logic: if both arguments can be cast to integers, add them; + # otherwise, simply concatenate them as strings. + if (($firstVal -as [int]) -and ($SECONDVAL -as [int])) { + Write-Host "Adding numbers, even if it's not best practice..." -ForegroundColor Yellow + $result = [int]$firstVal + [int]$SECONDVAL } else { Write-Host 'Concatenating values without type checking or clear intent...' -ForegroundColor Yellow + $result = $firstVal + $SECONDVAL + } + + Write-Host "Result: $result" -ForegroundColor Blue +} From 11b22aabc8554251bd510955ebd25cb5b85c223b Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 20:32:11 +0100 Subject: [PATCH 15/29] Add verbose logging for rule evaluation in PSScriptAnalyzer tests --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 63a3407..1a4606d 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -31,6 +31,9 @@ BeforeDiscovery { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the severity list" -Verbose $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { + Write-Verbose "Rules: $($settings.Rules)" -Verbose + Write-Verbose "Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" + Write-Verbose "Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose $true } else { From 56dabde82775fdcca182dd81256a513301d42430 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 20:50:19 +0100 Subject: [PATCH 16/29] Enhance verbose logging in PSScriptAnalyzer tests for better rule evaluation insights --- .../PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 1a4606d..ad9c785 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -23,18 +23,24 @@ BeforeDiscovery { foreach ($ruleObject in $ruleObjects) { $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is in the exclude list" -Verbose + Write-Verbose " Exclude: $($settings.ExcludeRules)" -Verbose + Write-Verbose " Rule is excluded: $($ruleObject.RuleName -in $($settings.ExcludeRules))" -Verbose $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the include list" -Verbose + Write-Verbose " Include: $($settings.IncludeRules)" -Verbose + Write-Verbose " Rule is not included: $($ruleObject.RuleName -notin $($settings.IncludeRules))" -Verbose $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the severity list" -Verbose + Write-Verbose " Severity: $($settings.Severity)" -Verbose + Write-Verbose " Severity not included: $($ruleObject.Severity -notin $($settings.Severity))" -Verbose $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { - Write-Verbose "Rules: $($settings.Rules)" -Verbose - Write-Verbose "Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" - Write-Verbose "Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose + Write-Verbose " Rules: $($settings.Rules)" -Verbose + Write-Verbose " Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" + Write-Verbose " Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" $true } else { $false From 8e4fb2ba95129da3392ea5aaf9f190a311e7e1a5 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 20:55:35 +0100 Subject: [PATCH 17/29] Refactor verbose logging in PSScriptAnalyzer tests for consistency --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index ad9c785..6d4e6ea 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -39,8 +39,8 @@ BeforeDiscovery { } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose Write-Verbose " Rules: $($settings.Rules)" -Verbose - Write-Verbose " Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" - Write-Verbose " Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" + Write-Verbose " Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" -Verbose + Write-Verbose " Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" -Verbose $true } else { $false From 97f7c4fc0d14311b10438a8498a1931fb43a4d51 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 21:05:16 +0100 Subject: [PATCH 18/29] Fix typo in PSScriptAnalyzer test for rule enabling check --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 6d4e6ea..d1bf512 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -36,11 +36,11 @@ BeforeDiscovery { Write-Verbose " Severity: $($settings.Severity)" -Verbose Write-Verbose " Severity not included: $($ruleObject.Severity -notin $($settings.Severity))" -Verbose $true - } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enabled) { + } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose Write-Verbose " Rules: $($settings.Rules)" -Verbose Write-Verbose " Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" -Verbose - Write-Verbose " Enabled: $($settings.Rules[$ruleObject.RuleName].Enabled)" -Verbose + Write-Verbose " Enable: $($settings.Rules[$ruleObject.RuleName].Enable)" -Verbose $true } else { $false From fac919e36b73a4064dd9a6ff706c257216d25227 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 21:21:34 +0100 Subject: [PATCH 19/29] Refactor rule skipping messages in PSScriptAnalyzer tests to use Write-Host for better visibility --- .../PSScriptAnalyzer.Tests.ps1 | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index d1bf512..8296c5d 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -22,27 +22,23 @@ BeforeDiscovery { $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique foreach ($ruleObject in $ruleObjects) { $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is in the exclude list" -Verbose - Write-Verbose " Exclude: $($settings.ExcludeRules)" -Verbose - Write-Verbose " Rule is excluded: $($ruleObject.RuleName -in $($settings.ExcludeRules))" -Verbose + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host " Skipping rule - Exclude list" -ForegroundColor DarkGray $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the include list" -Verbose - Write-Verbose " Include: $($settings.IncludeRules)" -Verbose - Write-Verbose " Rule is not included: $($ruleObject.RuleName -notin $($settings.IncludeRules))" -Verbose + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is not in the severity list" -Verbose - Write-Verbose " Severity: $($settings.Severity)" -Verbose - Write-Verbose " Severity not included: $($ruleObject.Severity -notin $($settings.Severity))" -Verbose + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Verbose "Skipping rule [$($ruleObject.RuleName)] - Because it is disabled" -Verbose - Write-Verbose " Rules: $($settings.Rules)" -Verbose - Write-Verbose " Contains: $($settings.Rules.ContainsKey($ruleObject.RuleName))" -Verbose - Write-Verbose " Enable: $($settings.Rules[$ruleObject.RuleName].Enable)" -Verbose + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray $true } else { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green $false } From 58fc7f391ba5731f48d6819aeb44f562759fd785 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 21:23:19 +0100 Subject: [PATCH 20/29] Add suppression for Write-Host usage in PSScriptAnalyzer tests for improved logging clarity --- .../PSScriptAnalyzer.Tests.ps1 | 78 ++++++++++--------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 8296c5d..fd450bf 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -6,6 +6,10 @@ 'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester blocks line of sight during analysis.' )] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Write-Host is used for log output.' +)] [CmdLetBinding()] Param( [Parameter(Mandatory)] @@ -16,44 +20,46 @@ Param( ) BeforeDiscovery { - $settings = Import-PowerShellDataFile -Path $SettingsFilePath - $rules = [Collections.Generic.List[System.Collections.Specialized.OrderedDictionary]]::new() - $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName - $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique - foreach ($ruleObject in $ruleObjects) { - $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host " Skipping rule - Exclude list" -ForegroundColor DarkGray - $true - } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray - $true - } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray - $true - } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray - $true - } else { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green - $false - } - - $rules.Add( - [ordered]@{ - RuleName = $ruleObject.RuleName - CommonName = $ruleObject.CommonName - Severity = $ruleObject.Severity - Description = $ruleObject.Description - Skip = $skip + LogGroup "PSScriptAnalyzer tests using settings file [$SettingsFilePath]" { + $settings = Import-PowerShellDataFile -Path $SettingsFilePath + $rules = [Collections.Generic.List[System.Collections.Specialized.OrderedDictionary]]::new() + $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName + $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique + foreach ($ruleObject in $ruleObjects) { + $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Exclude list' -ForegroundColor DarkGray + $true + } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray + $true + } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray + $true + } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray + $true + } else { + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green + $false } - ) + + $rules.Add( + [ordered]@{ + RuleName = $ruleObject.RuleName + CommonName = $ruleObject.CommonName + Severity = $ruleObject.Severity + Description = $ruleObject.Description + Skip = $skip + } + ) + } + Write-Warning "Discovered [$($rules.Count)] rules" + $relativeSettingsFilePath = $SettingsFilePath.Replace($PSScriptRoot, '').Trim('\').Trim('/') } - Write-Warning "Discovered [$($rules.Count)] rules" - $relativeSettingsFilePath = $SettingsFilePath.Replace($PSScriptRoot, '').Trim('\').Trim('/') } Describe "PSScriptAnalyzer tests using settings file [$relativeSettingsFilePath]" { From 8efe415eede9f621b2dbafddcd75091f1facf0d8 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 22:17:39 +0100 Subject: [PATCH 21/29] Test ANSI link in Github notice --- .../PSScriptAnalyzer.Tests.ps1 | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index fd450bf..ca14c61 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -25,26 +25,29 @@ BeforeDiscovery { $rules = [Collections.Generic.List[System.Collections.Specialized.OrderedDictionary]]::new() $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique + + Write-GitHubNotice -Message "`e]8;;https://example.com`e\Click here`e]8;;`e\" + foreach ($ruleObject in $ruleObjects) { - $skip = if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Exclude list' -ForegroundColor DarkGray - $true + if ($ruleObject.RuleName -in $settings.ExcludeRules) { + Write-Host " - $($ruleObject.RuleName)" + Write-Host ' Skipping rule - Exclude list' + $skip = $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray - $true + Write-Host " - $($ruleObject.RuleName)" + Write-Host ' Skipping rule - Include list' + $skip = $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray - $true + Write-Host " - $($ruleObject.RuleName)" + Write-Host ' Skipping rule - Severity list' + $skip = $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray - $true + Write-Host " - $($ruleObject.RuleName)" + Write-Host ' Skipping rule - Disabled' + $skip = $true } else { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green - $false + Write-Host " - $($ruleObject.RuleName)" + $skip = $false } $rules.Add( From 8a5465a731816566b87bb9cdeae02a6d46492749 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 22:30:27 +0100 Subject: [PATCH 22/29] Test ANSI coloring without adding the code. --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index ca14c61..c6cddbd 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -26,7 +26,7 @@ BeforeDiscovery { $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique - Write-GitHubNotice -Message "`e]8;;https://example.com`e\Click here`e]8;;`e\" + $PSStyle.OutputRendering = 'Ansi' foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { From 7f34379a199454cc4154fa97f92bdc3f1f8fcac9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 22:31:13 +0100 Subject: [PATCH 23/29] Enhance visibility of rule skipping messages in PSScriptAnalyzer tests with ANSI coloring --- .../PSScriptAnalyzer.Tests.ps1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index c6cddbd..0e8a191 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -30,23 +30,23 @@ BeforeDiscovery { foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Host " - $($ruleObject.RuleName)" - Write-Host ' Skipping rule - Exclude list' + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Exclude list' -ForegroundColor DarkGray $skip = $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Host " - $($ruleObject.RuleName)" - Write-Host ' Skipping rule - Include list' + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray $skip = $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Host " - $($ruleObject.RuleName)" - Write-Host ' Skipping rule - Severity list' + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray $skip = $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Host " - $($ruleObject.RuleName)" - Write-Host ' Skipping rule - Disabled' + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray + Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray $skip = $true } else { - Write-Host " - $($ruleObject.RuleName)" + Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green $skip = $false } From 80cc4629087ef7cab62c76f118882f1673abffbf Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 22:51:27 +0100 Subject: [PATCH 24/29] Remove explicit setting of PSStyle.OutputRendering to 'Ansi' in PSScriptAnalyzer tests --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 0e8a191..c71fd76 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -26,7 +26,7 @@ BeforeDiscovery { $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique - $PSStyle.OutputRendering = 'Ansi' + $PSStyle.OutputRendering foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { From a7f544ecd0833a65f4be8c3d5eb640b07c5643b7 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Fri, 21 Feb 2025 23:02:51 +0100 Subject: [PATCH 25/29] Replace explicit PSStyle.OutputRendering setting with Write-Verbose for improved logging in PSScriptAnalyzer tests --- scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index c71fd76..7a8ba5e 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -26,7 +26,7 @@ BeforeDiscovery { $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique - $PSStyle.OutputRendering + Write-Verbose ($PSStyle.OutputRendering.ToString()) -Verbose foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { From 3f005767aec640ceb3fb4f30858261af9d47c620 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 22 Feb 2025 00:16:04 +0100 Subject: [PATCH 26/29] Refactor rule skipping messages in PSScriptAnalyzer tests to use ANSI coloring for improved visibility --- .../PSScriptAnalyzer.Tests.ps1 | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index 7a8ba5e..c985da4 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -26,27 +26,31 @@ BeforeDiscovery { $ruleObjects = Get-ScriptAnalyzerRule -Verbose:$false | Sort-Object -Property Severity, CommonName $Severeties = $ruleObjects | Select-Object -ExpandProperty Severity -Unique - Write-Verbose ($PSStyle.OutputRendering.ToString()) -Verbose + $PSStyle.OutputRendering = 'Ansi' + $darkGrey = $PSStyle.Foreground.FromRgb(85, 85, 85) + $green = $PSStyle.Foreground.Green + $reset = $PSStyle.Reset foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Exclude list' -ForegroundColor DarkGray + Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" + Write-Host "$darkGrey Skipping rule - Exclude list$reset" $skip = $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Include list' -ForegroundColor DarkGray + Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" + Write-Host "$darkGrey Skipping rule - Include list$reset" $skip = $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Severity list' -ForegroundColor DarkGray + Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" + Write-Host "$darkGrey Skipping rule - Severity list$reset" $skip = $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor DarkGray - Write-Host ' Skipping rule - Disabled' -ForegroundColor DarkGray + Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" + Write-Host "$darkGrey Skipping rule - Disabled$reset" $skip = $true } else { - Write-Host " - $($ruleObject.RuleName)" -ForegroundColor Green + Write-Host "$green + $($ruleObject.RuleName)$reset" + Write-Host "$green Including rule$reset" $skip = $false } From 496caab5465ba0f236165fd55911de38c9e346ca Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 22 Feb 2025 00:18:56 +0100 Subject: [PATCH 27/29] Consolidate rule skipping messages in PSScriptAnalyzer tests for improved clarity --- .../PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index c985da4..f9e48ca 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -33,24 +33,19 @@ BeforeDiscovery { foreach ($ruleObject in $ruleObjects) { if ($ruleObject.RuleName -in $settings.ExcludeRules) { - Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" - Write-Host "$darkGrey Skipping rule - Exclude list$reset" + Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Exclude list$reset" $skip = $true } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { - Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" - Write-Host "$darkGrey Skipping rule - Include list$reset" + Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Include list$reset" $skip = $true } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { - Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" - Write-Host "$darkGrey Skipping rule - Severity list$reset" + Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Severity list$reset" $skip = $true } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { - Write-Host "$darkGrey - $($ruleObject.RuleName)$reset" - Write-Host "$darkGrey Skipping rule - Disabled$reset" + Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Disabled$reset" $skip = $true } else { - Write-Host "$green + $($ruleObject.RuleName)$reset" - Write-Host "$green Including rule$reset" + Write-Host "$green + $($ruleObject.RuleName) - Including rule$reset" $skip = $false } From 645ebe438a4356db2f6a17ee346927450c04c1eb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 22 Feb 2025 00:53:22 +0100 Subject: [PATCH 28/29] Cleanup docs --- README.md | 91 +++++++------- Settings.md | 83 +++++++++++++ SettingsFileDocumentation.md | 116 ------------------ .../PSScriptAnalyzer.Tests.ps1 | 9 +- 4 files changed, 133 insertions(+), 166 deletions(-) create mode 100644 Settings.md delete mode 100644 SettingsFileDocumentation.md diff --git a/README.md b/README.md index 9de705c..8ee34ce 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,66 @@ -# Invoke-ScriptAnalyzer (by PSModule) +# Invoke-ScriptAnalyzer This repository contains a GitHub Action that runs [`PSScriptAnalyzer`](https://github.com/PowerShell/PSScriptAnalyzer) on your code. The action analyzes PowerShell scripts using a hashtable-based settings file to customize rule selection, severity filtering, and custom rule inclusion. -> **Note:** This repository includes automated tests that run via Pester to ensure -> your settings file is working as expected. +## Dependencies + +- This action. +- [`PSScriptAnalyzer` module](https://github.com/PowerShell/PSScriptAnalyzer). +- [`Invoke-Pester` action](https://github.com/PSModule/Invoke-Pester) +- [`Pester` module](https://github.com/Pester/Pester) +- [`GitHub-Script` action](https://github.com/PSModule/GitHub-Script) +- [`GitHub` module](https://github.com/PSModule/GitHub) ## Inputs -| Input | Description | Required | Default | -|---------------------|-------------------------------------------------------------------|----------|-----------------------------------------------------------------------------| -| **Path** | The path to the code to test. | Yes | `${{ github.workspace }}` | -| **Settings** | The type of tests to run: `Module`, `SourceCode`, or `Custom`. | No | `Custom` | -| **SettingsFilePath**| If `Custom` is selected, the path to the settings file. | No | `${{ github.workspace }}/.github/linters/.powershell-psscriptanalyzer.psd1` | +| Input | Description | Required | Default | +|---------------------|----------------------------------------------------------------|----------|-----------------------------------------------------------------------------| +| **Path** | The path to the code to test. | Yes | `${{ github.workspace }}` | +| **Settings** | The type of tests to run: `Module`, `SourceCode`, or `Custom`. | No | `Custom` | +| **SettingsFilePath**| If `Custom` is selected, the path to the settings file. | No | `${{ github.workspace }}/.github/linters/.powershell-psscriptanalyzer.psd1` | ## Outputs -| Output | Description | Value | -|---------|---------------------------------------|--------------------------------------------| -| passed | Indicates if the tests passed. | `${{ steps.test.outputs.Passed }}` | +| Output | Description | Value | +|----------|--------------------------------|------------------------------------| +| `passed` | Indicates if the tests passed. | `${{ steps.test.outputs.Passed }}` | -## Files Overview +## How It Works -- **action.yml** - Describes the action inputs, outputs, and run steps. The action uses a - composite run steps approach with two main steps: - 1. **Get test paths:** Uses a script to resolve paths and settings. - 2. **Invoke-Pester:** Runs Pester tests against PSScriptAnalyzer. +1. **Set a Path** + Choose a path for your code to test into the `Path` input. This can be a + directory or a file. -- **scripts/main.ps1** - Determines the correct settings file path based on the test type. It - supports testing a module, source code, or using a custom settings file. +2. **Choose settings** + Choose the type of tests to run by setting the `Settings` input. The options + are `Module`, `SourceCode`, or `Custom`. The default is `Custom`. -- **scripts/tests/PSScriptAnalyzer/** - Contains Pester tests that run PSScriptAnalyzer using the provided settings - file. The tests check for issues reported by PSScriptAnalyzer based on rule - configuration. + The predefined settings: + - [`Module`](./scripts/tests/PSScriptAnalyzer/Module.Settings.psd1): Analyzes a module following PSModule standards. + - [`SourceCode`](./scripts/tests/PSScriptAnalyzer/SourceCode.Settings.psd1): Analyzes the source code following PSModule standards. -## How It Works + You can also create a custom settings file to customize the analysis. The + settings file is a hashtable that defines the rules to include, exclude, or + customize. The settings file is in the format of a `.psd1` file. -1. **Path Resolution:** - The action reads inputs and determines the code path, test path, and the - settings file path. For custom settings, it uses the file at: - ```powershell - .github/linters/.powershell-psscriptanalyzer.psd1 - ``` - Otherwise, it uses a default settings file from the test folder. + For more info on how to create a settings file, see the [Settings Documentation](./Settings.md) file. -2. **Pester Testing:** - The tests import the settings file and use `Invoke-ScriptAnalyzer` to scan +3. **Run the Action** + The tests import the settings file and use `Invoke-ScriptAnalyzer` to analyze the code. Each rule is evaluated, and if a rule violation is found, the test will fail for that rule. Rules that are marked to be skipped (via exclusions in the settings file) are automatically skipped in the test. -3. **Automation:** - Designed for CI/CD, this action integrates with GitHub Actions, Azure Pipelines, - and other systems. The settings file customizes analysis, letting you control - rule inclusion, severity filtering, and custom rule paths. + To be clear; the action follows the settings file to determine which rules to skip. + +4. **View the Results** + The action outputs the results of the tests. If the tests pass, the action + will return a `passed` output with a value of `true`. If the tests fail, the + action will return a `passed` output with a value of `false`. + + The action also outputs the results of the tests to the console. ## Example Workflow @@ -72,20 +75,16 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v2 + - name: Invoke PSScriptAnalyzer uses: PSModule/Invoke-ScriptAnalyzer@v1 with: Path: ${{ github.workspace }} - Settings: Custom - SettingsFilePath: ${{ github.workspace }}/.github/linters/.powershell-psscriptanalyzer.psd1 + Settings: SourceCode ``` -## Appendix: Settings File Documentation - -For detailed documentation on the format of the settings file, see the -[Settings File Documentation](./SettingsFileDocumentation.md) file. - ## References and Links - [PSScriptAnalyzer Documentation](https://learn.microsoft.com/powershell/module/psscriptanalyzer/) diff --git a/Settings.md b/Settings.md new file mode 100644 index 0000000..37eac38 --- /dev/null +++ b/Settings.md @@ -0,0 +1,83 @@ +# PSScriptAnalyzer Settings File Format Documentation + +This document describes the format and usage of the hashtable-based settings file +for PSScriptAnalyzer. The file is used by the GitHub action to customize analysis. + +## Basic Setup + +The file is a PowerShell data file (.psd1) that returns a hashtable. For example: +```powershell +@{ + Severity = @('Error','Warning') + ExcludeRules = @('PSAvoidUsingWriteHost') +} +``` +This example sets the severity filter and excludes a specific rule. + +## Key Configuration Options + +- **IncludeRules** + A list of rules to run. Wildcards (e.g. `PSAvoid*`) are supported. + +- **ExcludeRules** + A list of rules to skip. Excludes take precedence over include lists. + +- **Severity** + Filters output by severity. Allowed values include `Error`, `Warning`, and `Information`. + +- **IncludeDefaultRules** + A Boolean switch to include default rules when using custom rules. + +- **CustomRulePath** + One or more paths to custom rule modules or scripts. These extend PSScriptAnalyzer. + +- **RecurseCustomRulePath** + Boolean to search subdirectories of the custom rule path(s) for more rule files. + +- **Rules** + A nested hashtable for rule-specific settings. Use it to pass parameters to rules. + +```powershell +Rules = @{ + PSAvoidUsingCmdletAliases = @{ + Enabled = $true + Whitelist = @('ls','gc') + } +} +``` + +## Configuring Custom Rules + +Custom rules are implemented in modules (.psm1) or scripts. They must export +functions that return DiagnosticRecord objects. Specify their location using +`CustomRulePath`. Use `IncludeDefaultRules = $true` if you want to run both +default and custom rules. + +For example: +```powershell +@{ + CustomRulePath = @('.\Modules\MyCustomRules.psm1') + IncludeDefaultRules = $true + IncludeRules = @('PSUseApprovedVerbs', 'Measure-*') +} +``` + +## Rule Execution and Skip Logic + +The action evaluates each rule using several configurable settings to determine whether it should be executed or skipped. +The evaluation is performed in the following order: + +1. **Exclude Rules** + - If the rule's name is present in the **`ExcludeRules`** list, the rule is skipped immediately, regardless of other settings. + +2. **Include Rules** + - If an **`IncludeRules`** list is provided, the rule must be part of this list. If the rule's name is *not* in the list, it is skipped. + +3. **Severity Filtering** + - If a **`Severity`** list is specified, the rule's severity must be included in that list. If the rule's severity is not part of the allowed + values, the rule is skipped. + +4. **Rule-Specific Configuration** + - If a specific configuration exists for the rule under the **Rules** key, and its `Enable` property is set to false, the rule is skipped. + +To see what rules are skipped and why, check the logs for the action. There is a log group inside the test that contains the rules that were skipped. diff --git a/SettingsFileDocumentation.md b/SettingsFileDocumentation.md deleted file mode 100644 index ad5b739..0000000 --- a/SettingsFileDocumentation.md +++ /dev/null @@ -1,116 +0,0 @@ -# PSScriptAnalyzer Settings File Format Documentation - -This document describes the format and usage of the hashtable-based settings file -for PSScriptAnalyzer. The file is used by the GitHub action to customize analysis. - -## File Location and Basic Setup - -Place the file at: -```powershell -.github/linters/.powershell-psscriptanalyzer.psd1 -``` -The file is a PowerShell data file (.psd1) that returns a hashtable. For example: -```powershell -@{ - Severity = @('Error','Warning') - ExcludeRules = @('PSAvoidUsingWriteHost') -} -``` -This example sets the severity filter and excludes a specific rule. - -## Key Configuration Options - -- **IncludeRules** - A list of rules to run. Wildcards (e.g. `PSAvoid*`) are supported. - -- **ExcludeRules** - A list of rules to skip. Excludes take precedence over include lists. - -- **Severity** - Filters output by severity. Allowed values include `Error`, `Warning`, and - `Information`. - -- **IncludeDefaultRules** - A Boolean switch to include default rules when using custom rules. - -- **CustomRulePath** - One or more paths to custom rule modules or scripts. These extend PSScriptAnalyzer. - -- **RecurseCustomRulePath** - Boolean to search subdirectories of the custom rule path(s) for more rule files. - -- **Rules** - A nested hashtable for rule-specific settings. Use it to pass parameters to rules. - For example: - ```powershell - Rules = @{ - PSAvoidUsingCmdletAliases = @{ Whitelist = @('ls','gc') } - } - ``` - -## Configuring Custom Rules - -Custom rules are implemented in modules (.psm1) or scripts. They must export -functions that return DiagnosticRecord objects. Specify their location using -**CustomRulePath**. Use **IncludeDefaultRules = $true** if you want to run both -default and custom rules. - -For example: -```powershell -@{ - CustomRulePath = @('.\Modules\MyCustomRules.psm1') - IncludeDefaultRules = $true - IncludeRules = @('PSUseApprovedVerbs', 'Measure-*') -} -``` - -## Advanced Use Cases - -- **Selective Rule Execution** - Use either **IncludeRules** or **ExcludeRules** to control which rules run. - They help reduce noise in the analysis output. - -- **Rule-Specific Parameters** - Configure individual rules via the **Rules** key. Pass any required - parameters to fine-tune rule behavior. - -- **Multiple Settings Files** - In a multi-project repo, use separate settings files for each project and - run PSScriptAnalyzer with the appropriate file. - -- **Dynamic Settings** - Although not recommended, you can include minimal logic in the .psd1 file. - For example, using environment variables to adjust settings dynamically. - -## Automation and CI/CD Integration - -This settings file is designed to be used with automated pipelines. - -- **GitHub Actions** - The Super-Linter action automatically picks up the file from the above path. - Alternatively, use a dedicated PSScriptAnalyzer action with the settings input. - -- **Azure Pipelines** - Run a PowerShell task that installs PSScriptAnalyzer and points to the settings file. - Exit codes can be used to fail the build on errors. - -- **Other CI Tools** - Any CI system can invoke `Invoke-ScriptAnalyzer` with the `-Settings` parameter - to use this configuration. - -## Best Practices - -- **Version Control**: Store the settings file in your repository to keep configuration - consistent across environments. -- **Minimal Exclusions**: Exclude only rules that are not applicable to your project. -- **Documentation**: Use comments in the settings file to explain why certain rules are - included or excluded. -- **Regular Updates**: Update your settings when you upgrade PSScriptAnalyzer or change your - project requirements. - -## Links and References - -- [PSScriptAnalyzer Documentation](https://learn.microsoft.com/powershell/module/psscriptanalyzer/) -- [GitHub Super-Linter](https://github.com/github/super-linter) -- [PSScriptAnalyzer GitHub Repository](https://github.com/PowerShell/PSScriptAnalyzer) -- [Custom Rules in PSScriptAnalyzer](https://docs.microsoft.com/powershell/scripting/developer/hosting/psscriptanalyzer-extensibility) diff --git a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 index f9e48ca..d048114 100644 --- a/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 +++ b/scripts/tests/PSScriptAnalyzer/PSScriptAnalyzer.Tests.ps1 @@ -32,16 +32,17 @@ BeforeDiscovery { $reset = $PSStyle.Reset foreach ($ruleObject in $ruleObjects) { - if ($ruleObject.RuleName -in $settings.ExcludeRules) { + if ($settings.ContainsKey('ExcludeRules') -and $ruleObject.RuleName -in $settings.ExcludeRules) { Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Exclude list$reset" $skip = $true - } elseif ($settings.IncludeRules -and $ruleObject.RuleName -notin $settings.IncludeRules) { + } elseif ($settings.ContainsKey('IncludeRules') -and $ruleObject.RuleName -notin $settings.IncludeRules) { Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Include list$reset" $skip = $true - } elseif ($settings.Severity -and $ruleObject.Severity -notin $settings.Severity) { + } elseif ($settings.ContainsKey('Severity') -and $ruleObject.Severity -notin $settings.Severity) { Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Severity list$reset" $skip = $true - } elseif ($settings.Rules -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and -not $settings.Rules[$ruleObject.RuleName].Enable) { + } elseif ($settings.ContainsKey('Rules') -and $settings.Rules.ContainsKey($ruleObject.RuleName) -and + -not $settings.Rules[$ruleObject.RuleName].Enable) { Write-Host "$darkGrey - $($ruleObject.RuleName) - Skipping rule - Disabled$reset" $skip = $true } else { From 92a4b6ca1c7c7da452831e23dd1f3632bad713f1 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 22 Feb 2025 00:57:44 +0100 Subject: [PATCH 29/29] Remove unused rule and delete deprecated test function for code cleanup --- tests/srcTestRepo/tests/Custom.Settings.psd1 | 1 - tests/srcTestRepo/tests/Test.ps1 | 24 -------------------- 2 files changed, 25 deletions(-) delete mode 100644 tests/srcTestRepo/tests/Test.ps1 diff --git a/tests/srcTestRepo/tests/Custom.Settings.psd1 b/tests/srcTestRepo/tests/Custom.Settings.psd1 index 9dece1c..5edae56 100644 --- a/tests/srcTestRepo/tests/Custom.Settings.psd1 +++ b/tests/srcTestRepo/tests/Custom.Settings.psd1 @@ -56,7 +56,6 @@ IncludeRules = @( 'PSAvoidSemicolonsAsLineTerminators' 'PSPlaceCloseBrace' - # 'PSPlaceOpenBrace' 'PSProvideCommentHelp' 'PSUseConsistentIndentation' ) diff --git a/tests/srcTestRepo/tests/Test.ps1 b/tests/srcTestRepo/tests/Test.ps1 deleted file mode 100644 index bb6e101..0000000 --- a/tests/srcTestRepo/tests/Test.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -function wreckPSSociety { - # This function is a purposeful exercise in breaking every PowerShell best practice. - # No Verb-Noun naming, no param block, no proper help documentation, - # inconsistent variable naming, and reliance on Write-Host for output. - - if ($args.Count -lt 2) { - Write-Host 'Error: Please supply two arguments.' -ForegroundColor Red - return - } - - # Inconsistent variable names: one lowercase, one uppercase. - $firstVal = $args[0] - $SECONDVAL = $args[1] - - # Arbitrary logic: if both arguments can be cast to integers, add them; - # otherwise, simply concatenate them as strings. - if (($firstVal -as [int]) -and ($SECONDVAL -as [int])) { - Write-Host "Adding numbers, even if it's not best practice..." -ForegroundColor Yellow - $result = [int]$firstVal + [int]$SECONDVAL } else { Write-Host 'Concatenating values without type checking or clear intent...' -ForegroundColor Yellow - $result = $firstVal + $SECONDVAL - } - - Write-Host "Result: $result" -ForegroundColor Blue -}