Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.3.1] 2025-12-14

### Fixed

- `Measure-BasicWebRequestProperty`: AST search modified to fix duplicate errors
due to recursive search.
- `Measure-InvokeWebRequestWithoutBasic`: AST search modified to fix duplicate
errors due to recursive search.

## [0.3.0] 2025-12-13

### Added
Expand Down
2 changes: 1 addition & 1 deletion GoodEnoughRules/GoodEnoughRules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
RootModule = 'GoodEnoughRules.psm1'

# Version number of this module.
ModuleVersion = '0.3.0'
ModuleVersion = '0.3.1'

# Supported PSEditions
# CompatiblePSEditions = @()
Expand Down
4 changes: 2 additions & 2 deletions GoodEnoughRules/Public/Measure-BasicWebRequestProperty.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function Measure-BasicWebRequestProperty {

process {
# Find all member expression ASTs that match our criteria
[System.Management.Automation.Language.Ast[]]$memberReads = $ScriptBlockAst.FindAll($iwrMemberRead, $true)
[System.Management.Automation.Language.Ast[]]$memberReads = $ScriptBlockAst.FindAll($iwrMemberRead, $false)
foreach ($memberRead in $memberReads) {
# ParenExpression would be the whole line: (iwr -Uri ... -UseBasicParsing).Foo
$parenExpression = $memberRead.Parent.Parent
Expand All @@ -89,7 +89,7 @@ function Measure-BasicWebRequestProperty {
}
}
# Find all assignment ASTs that match our criteria
[System.Management.Automation.Language.Ast[]]$assignments = $ScriptBlockAst.FindAll($varAssignPredicate, $true)
[System.Management.Automation.Language.Ast[]]$assignments = $ScriptBlockAst.FindAll($varAssignPredicate, $false)
# Now use that to search for var reads of the assigned variable
foreach ($assignment in $assignments) {
$variableName = $assignment.Left.VariablePath.UserPath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function Measure-InvokeWebRequestWithoutBasic {
}

process {
[System.Management.Automation.Language.Ast[]]$commands = $ScriptBlockAst.FindAll($predicate, $true)
[System.Management.Automation.Language.Ast[]]$commands = $ScriptBlockAst.FindAll($predicate, $false)
$commands | ForEach-Object {
Write-Verbose "Analyzing command: $($_.GetCommandName())"
$command = $_
Expand Down
11 changes: 6 additions & 5 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
switch ($Parameter) {
'Task' {
if ([string]::IsNullOrEmpty($WordToComplete)) {
Get-PSakeScriptTasks -buildFile $psakeFile | Select-Object -ExpandProperty Name
Get-PSakeScriptTasks -BuildFile $psakeFile | Select-Object -ExpandProperty Name
} else {
Get-PSakeScriptTasks -buildFile $psakeFile |
Get-PSakeScriptTasks -BuildFile $psakeFile |
Where-Object { $_.Name -match $WordToComplete } |
Select-Object -ExpandProperty Name
}
}
Default {
default {
}
}
})]
Expand Down Expand Up @@ -55,10 +55,11 @@
# Execute psake task(s)
$psakeFile = './psakeFile.ps1'
if ($PSCmdlet.ParameterSetName -eq 'Help') {
Get-PSakeScriptTasks -buildFile $psakeFile |
Get-PSakeScriptTasks -BuildFile $psakeFile |
Format-Table -Property Name, Description, Alias, DependsOn
} else {
Invoke-PSDepend -Path './requirements.psd1' -Import -Force -WarningAction SilentlyContinue
Set-BuildEnvironment -Force
Invoke-psake -buildFile $psakeFile -taskList $Task -NoLogo -properties $Properties -parameters $Parameters
Invoke-psake -buildFile $psakeFile -taskList $Task -nologo -properties $Properties -parameters $Parameters

Check warning on line 63 in build.ps1

View workflow job for this annotation

GitHub Actions / ci / Run Linters

Unknown word (nologo) Suggestions: (nolo, nolock, nonego, neology, onload)
exit ([int](-not $psake.build_success))
}
18 changes: 16 additions & 2 deletions tests/Measure-BasicWebRequestProperty.tests.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
Describe 'Measure-TODOComment' {
Describe 'Measure-BasicWebRequestProperty' {
BeforeAll {
if ( -not $env:BHPSModuleManifest ) {
.\build.ps1 -Task Build -Verbose
Set-BuildEnvironment -Path "$PSScriptRoot\.." -Force
}
$manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest
$outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output'
$outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName
$outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion
$script:outputModVerModule = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psm1"
$outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1"

# Get module commands
Expand All @@ -24,6 +25,19 @@ Describe 'Measure-TODOComment' {
$result[0].Message | Should -Be "Invoke-WebRequest cannot use the 'Forms' parameter when 'UseBasicParsing' is specified."
}

It 'Detects another bad method usage' {
$file = "$PSScriptRoot\fixtures\ExampleFunction.ps1"
$invokeScriptAnalyzerSplat = @{
Path = $file
IncludeRule = 'Measure-BasicWebRequestProperty'
CustomRulePath = $script:outputModVerModule
}
$result = Invoke-ScriptAnalyzer @invokeScriptAnalyzerSplat
$result.Count | Should -BeExactly 2
$result[0].Message | Should -Be "Invoke-WebRequest cannot use the 'Forms' parameter when 'UseBasicParsing' is specified."
$result[1].Message | Should -Be "Invoke-WebRequest cannot use the 'AllElements' parameter when 'UseBasicParsing' is specified."
}

It 'does not detect correct usage of Images property' {
$fakeScript = '$bar = (iwr -Uri https://example.com -UseBasicParsing).Images'
$ast = [System.Management.Automation.Language.Parser]::ParseInput($fakeScript, [ref]$null, [ref]$null)
Expand Down
21 changes: 20 additions & 1 deletion tests/Measure-InvokeWebRequestWithoutBasic.tests.ps1
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
Describe 'Measure-InvokeWebRequestWithoutBasic' {
BeforeAll {
if ( -not $env:BHPSModuleManifest ) {
.\build.ps1 -Task Build -Verbose
Set-BuildEnvironment -Path "$PSScriptRoot\.." -Force
}
$manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest
$outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output'
$outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName
$outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion
$script:outputModVerModule = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psm1"
$outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1"

# Get module commands
# Remove all versions of the module from the session. Pester can't handle multiple versions.
Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore
Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop
Import-Module -Name 'PSScriptAnalyzer' -Verbose:$false -ErrorAction Inquire
}

Context 'When Invoke-WebRequest is used without UseBasicParsing' {
Expand All @@ -27,6 +29,23 @@ Invoke-WebRequest -Uri 'https://example.com'
$result[0].Severity | Should -Be 'Error'
}

It 'detects Invoke-WebRequest without UseBasicParsing in different formatting' {
$file = "$PSScriptRoot\fixtures\ExampleFunction.ps1"
$invokeScriptAnalyzerSplat = @{
Path = $file
IncludeRule = 'Measure-InvokeWebRequestWithoutBasic'
CustomRulePath = $script:outputModVerModule
}

$result = Invoke-ScriptAnalyzer @invokeScriptAnalyzerSplat
$result.Count | Should -BeExactly 2
$result[0].Message | Should -Be 'Invoke-WebRequest should be used with the UseBasicParsing parameter.'
$result[0].Severity | Should -Be 'Error'
$result[0].Line | Should -Be 6
$result[1].Message | Should -Be 'Invoke-WebRequest should be used with the UseBasicParsing parameter.'
$result[1].Severity | Should -Be 'Error'
}

It 'Detects iwr alias without UseBasicParsing' {
$fakeScript = @"
iwr -Uri 'https://example.com'
Expand Down
2 changes: 1 addition & 1 deletion tests/Measure-SecureStringWithKey.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Describe 'Measure-TODOComment' {
BeforeAll {
if ( -not $env:BHPSModuleManifest ) {
.\build.ps1 -Task Build -Verbose
Set-BuildEnvironment -Path "$PSScriptRoot\.." -Force
}
$manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest
$outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output'
Expand Down
2 changes: 1 addition & 1 deletion tests/Measure-TODOComment.tests.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Describe 'Measure-TODOComment' {
BeforeAll {
if ( -not $env:BHPSModuleManifest ) {
.\build.ps1 -Task Build -Verbose
Set-BuildEnvironment -Path "$PSScriptRoot\.." -Force
}
$manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest
$outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output'
Expand Down
20 changes: 20 additions & 0 deletions tests/fixtures/ExampleFunction.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function Get-Example {
[CmdletBinding()]
param ()

begin {
$beginIWR = Invoke-WebRequest -Uri "https://example.com"
}

process {
$processIWR = Invoke-WebRequest -Uri "https://example.org"
$processIWR
$badParam = Invoke-WebRequest -Uri "https://example.net" -UseBasicParsing
$badParam.Forms
}

end {
$beginIWR.Forms
$badParam.AllElements
}
}