Functions/GenXdev.Coding.PowerShell.Modules/Invoke-GenXdevScriptAnalyzer.ps1
<##############################################################################
Part of PowerShell module : GenXdev.Coding.PowerShell.Modules Original cmdlet filename : Invoke-GenXdevScriptAnalyzer.ps1 Original author : René Vaessen / GenXdev Version : 1.270.2025 ################################################################################ MIT License Copyright 2021-2025 GenXdev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ################################################################################> ################################################################################ <# .SYNOPSIS Invokes PowerShell Script Analyzer to analyze PowerShell scripts for compliance and best practices. .DESCRIPTION This function provides a wrapper around PSScriptAnalyzer to analyze PowerShell scripts for compliance issues, best practices violations, and potential bugs. It supports both file-based analysis and string-based script analysis with customizable rules and settings. .PARAMETER Path Specifies the path to the script file to analyze. This parameter is mandatory when using the Path parameter set. .PARAMETER ScriptDefinition Specifies the script definition as a string to analyze. This parameter is mandatory when using the Script parameter set. .PARAMETER EnableExit Specifies that the tool should exit on error during analysis. .PARAMETER Fix Enables automatic fixing of violations where possible. .PARAMETER Recurse Recursively processes files in subdirectories when analyzing a directory path. .PARAMETER ReportSummary Reports a summary after analysis showing the total number of issues found. .EXAMPLE Invoke-GenXdevScriptAnalyzer -Path "C:\Scripts\MyScript.ps1" .EXAMPLE Invoke-GenXdevScriptAnalyzer -ScriptDefinition "Get-Process | Where-Object {$_.Name -eq 'notepad'}" .EXAMPLE Invoke-GenXdevScriptAnalyzer -Path "C:\Scripts\" -Recurse -Fix #> function Invoke-GenXdevScriptAnalyzer { [CmdletBinding(DefaultParameterSetName = 'Path')] param ( # [Parameter( Position = 0, Mandatory = $true, ParameterSetName = 'Path', HelpMessage = 'Specifies the path to the script file.' )] [string] $Path, # [Parameter( Mandatory = $true, ParameterSetName = 'Script', HelpMessage = 'Specifies the script definition as a string.' )] [string] $ScriptDefinition, # [Parameter( Mandatory = $false, HelpMessage = 'Specifies that the tool should exit on error.' )] [switch] $EnableExit, # [Parameter( Mandatory = $false, HelpMessage = 'Enables automatic fixing of violations.' )] [switch] $Fix, # [Parameter( Mandatory = $false, HelpMessage = 'Recursively process files.' )] [switch] $Recurse, # [Parameter( Mandatory = $false, HelpMessage = 'Reports a summary after analysis.' )] [switch] $ReportSummary # ) begin { $loaded = Microsoft.PowerShell.Core\Get-Module -Name PSScriptAnalyzer -ErrorAction SilentlyContinue if (-not $loaded) { $folder = GenXdev.FileSystem\Expand-Path "$PSScriptRoot\..\..\..\..\PSScriptAnalyzer\1.24.0\" $path = GenXdev.FileSystem\Expand-Path "$folder\PSv7\GenXdev.Coding.PowerShell.Modules.ScriptAnalyzer.dll" if (-not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $folder)) { $null = PowerShellGet\Install-Module -Name PSScriptAnalyzer -RequiredVersion 1.24.0 -Scope CurrentUser -Force } if (-not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $path)) { $source = GenXdev.FileSystem\Expand-Path "$PSScriptRoot\..\..\assets\Modules\PSScriptAnalyzer\1.24.0\*" $null = GenXdev.FileSystem\Start-RoboCopy $source "$folder\" } $null = Microsoft.PowerShell.Core\Import-Module PSScriptAnalyzer } # load script analyzer settings from configuration file $settingsPath = "$PSScriptRoot\PSScriptAnalyzerSettings.psd1" $settings = Microsoft.PowerShell.Utility\Invoke-Expression ` ([System.IO.File]::ReadAllText($settingsPath)) # output verbose information about loaded settings Microsoft.PowerShell.Utility\Write-Verbose ` "Loaded PSScriptAnalyzer settings from: $settingsPath" } process { try { # initialize invocation parameters variable $invocationParams = $null # check which parameter set is being used if ($PSCmdlet.ParameterSetName -eq 'Path') { # configure parameters for path-based analysis $invocationParams = @{ Path = $Path IncludeRule = $settings.IncludeRules ExcludeRule = $settings.ExcludeRules CustomRulePath = $settings.CustomRulePath IncludeDefaultRules = $settings.IncludeDefaultRules RecurseCustomRulePath = $settings.RecurseCustomRulePath Recurse = [bool]$Recurse Fix = [bool]$Fix EnableExit = [bool]$EnableExit ReportSummary = [bool]$ReportSummary Severity = 'Warning' } # output verbose information about path analysis Microsoft.PowerShell.Utility\Write-Verbose ` "Analyzing script file: $Path" } else { # configure parameters for script definition analysis $invocationParams = @{ ScriptDefinition = $ScriptDefinition IncludeRule = $settings.IncludeRules ExcludeRule = $settings.ExcludeRules CustomRulePath = $settings.CustomRulePath IncludeDefaultRules = $settings.IncludeDefaultRules RecurseCustomRulePath = $settings.RecurseCustomRulePath Recurse = [bool]$Recurse Fix = [bool]$Fix EnableExit = [bool]$EnableExit ReportSummary = [bool]$ReportSummary Severity = 'Warning' } # output verbose information about script definition analysis Microsoft.PowerShell.Utility\Write-Verbose ` 'Analyzing script definition content' } [int] $retries = 3; while ($retries-- -gt 0) { try { # invoke script analyzer with configured parameters $results = @(PSScriptAnalyzer\Invoke-ScriptAnalyzer @invocationParams -Verbose:$false) # output verbose information about analysis results Microsoft.PowerShell.Utility\Write-Verbose ` "Analysis completed with $($results.Count) results" break; } catch { # output warning for script analyzer errors Microsoft.PowerShell.Utility\Write-Warning ` "ScriptAnalyzer error: $($_.Exception.Message)" if ($retries -eq 1) { return } Microsoft.PowerShell.Utility\Start-Sleep 1 } } # check if results were returned if ($results -and ($results.Length -gt 0)) { # process each result to enhance with additional information $results | Microsoft.PowerShell.Core\ForEach-Object { # convert result to hashtable for easier manipulation $resultHashTable = $_ | GenXdev.Helpers\ConvertTo-HashTable # add rule description to the result $resultHashTable.Description = ` (PSScriptAnalyzer\Get-ScriptAnalyzerRule ` -Name $resultHashTable.RuleName).Description # output the enhanced result Microsoft.PowerShell.Utility\Write-Output $resultHashTable } } } catch { # create error output for general exceptions $errorResult = @{ Message = $_.Exception.Message RuleName = ($null -eq $Path ? '?' : ` [System.IO.Path]::GetFileNameWithoutExtension($Path)) + ` ' @ Invocation in Invoke-GenXdevScriptAnalyzer' Description = 'An error occurred while invoking the Script Analyzer.' } # output the error result Microsoft.PowerShell.Utility\Write-Output $errorResult } } end { } } ################################################################################ |