{"id":26675462,"url":"https://github.com/heyitsgilbert/goodenoughrules","last_synced_at":"2026-07-04T03:31:31.146Z","repository":{"id":282579516,"uuid":"948790144","full_name":"HeyItsGilbert/GoodEnoughRules","owner":"HeyItsGilbert","description":"A set of PSScriptAnalyzer rules that help make it Good Enough!","archived":false,"fork":false,"pushed_at":"2025-03-15T14:59:22.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-15T15:32:53.452Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HeyItsGilbert.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"HeyItsGilbert"}},"created_at":"2025-03-15T01:00:05.000Z","updated_at":"2025-03-15T14:58:49.000Z","dependencies_parsed_at":"2025-03-15T15:43:04.377Z","dependency_job_id":null,"html_url":"https://github.com/HeyItsGilbert/GoodEnoughRules","commit_stats":null,"previous_names":["heyitsgilbert/goodenoughrules"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeyItsGilbert%2FGoodEnoughRules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeyItsGilbert%2FGoodEnoughRules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeyItsGilbert%2FGoodEnoughRules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HeyItsGilbert%2FGoodEnoughRules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HeyItsGilbert","download_url":"https://codeload.github.com/HeyItsGilbert/GoodEnoughRules/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245579724,"owners_count":20638679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-26T03:18:06.456Z","updated_at":"2026-07-04T03:31:31.141Z","avatar_url":"https://github.com/HeyItsGilbert.png","language":"PowerShell","funding_links":["https://github.com/sponsors/HeyItsGilbert"],"categories":[],"sub_categories":[],"readme":"# GoodEnoughRules\r\n\r\nA set of PSScriptAnalyzer rules that help make it Good Enough!\r\n\r\n## Badges\r\n\r\n| Downloads | Version | Publish Status | Supported Platforms |\r\n|---|---|---|---|\r\n| [![PowerShell Gallery][psgallery-downloads-badge]][psgallery] | [![PowerShell Gallery Version][psgallery-version-badge]][psgallery] | [![GitHub Workflow Status][build-badge]](https://github.com/HeyItsGilbert/GoodEnoughRules/actions/workflows/publish.yaml) | [![PowerShell Gallery][platform-badge]][psgallery] |\r\n\r\n## Overview\r\n\r\nThese are rules that _\"Good Enough\"_ Gilbert, slapped together after seeing\r\nsomeone or something that wanted it.  These may not be appropriate for your\r\nenvironment so keep that in mind when including them.\r\n\r\nYou will probably want to enable individual rules vs all of them at once.  I\r\nsuggest taking a look at the documents to see what each rule does. \r\n\r\n## Installation\r\n\r\nInstall from the [PowerShell Gallery][psgallery]:\r\n\r\n```powershell\r\nInstall-PSResource GoodEnoughRules\r\n```\r\n\r\n## Documentation\r\n\r\nThe docs are automatically generated from the rule comment based help. You can see the docs at [HeyItsGilbert.GitHub.io/GoodEnoughRules](https://heyitsgilbert.github.io/GoodEnoughRules)\r\n\r\n## Available Rules\r\n\r\n### Measure-TODOComment\r\n\r\n**Severity:** Information\r\n\r\nDetects TODO-style comments in your code, including TODO, FIXME, BUG, MARK, and checkbox-style comments (`[ ]`).\r\n\r\n```powershell\r\n# This will trigger the rule: \r\n# TODO:  Refactor this function\r\n# FIXME: Handle edge case\r\n```\r\n\r\n**Why it matters:** Helps track pending work items and ensures technical debt is documented and addressable.\r\n\r\n### Measure-InvokeWebRequestWithoutBasic\r\n\r\n**Severity:** Error\r\n\r\nDetects when `Invoke-WebRequest` (or its aliases `iwr`, `curl`) is used without the `UseBasicParsing` parameter.\r\n\r\n```powershell\r\n# This will trigger the rule: \r\nInvoke-WebRequest -Uri 'https://example.com'\r\n\r\n# This is preferred: \r\nInvoke-WebRequest -Uri 'https://example.com' -UseBasicParsing\r\n```\r\n\r\n**Why it matters:** `UseBasicParsing` avoids dependency on Internet Explorer's DOM parser, making scripts more portable and reliable, especially in server environments.\r\n\r\n### Measure-BasicWebRequestProperty\r\n\r\n**Severity:** Error\r\n\r\nDetects when `Invoke-WebRequest` is used with `UseBasicParsing` but then tries to access properties that are incompatible with basic parsing (like `Forms`, `ParsedHtml`, `Scripts`, `AllElements`).\r\n\r\n```powershell\r\n# This will trigger the rule:\r\n$response = Invoke-WebRequest -Uri 'https://example.com' -UseBasicParsing\r\n$forms = $response.Forms  # These properties aren't available with UseBasicParsing\r\n```\r\n\r\n**Why it matters:** Prevents runtime errors by catching incompatible property access at analysis time. \r\n\r\n### Measure-SecureStringWithKey\r\n\r\n**Severity:** Error\r\n\r\nDetects when `ConvertFrom-SecureString` is used without a `-Key` parameter, which means the encrypted string is bound to the specific user and machine.\r\n\r\n```powershell\r\n# This will trigger the rule:\r\n$secureString | ConvertFrom-SecureString\r\n\r\n# This is preferred for portability:\r\n$secureString | ConvertFrom-SecureString -Key $keyBytes\r\n```\r\n\r\n**Why it matters:** Without a key, encrypted strings cannot be decrypted on different machines or by different users, limiting portability and automation scenarios.\r\n\r\n### Measure-GremlinCharacter\r\n\r\n**Severity:** Varies (Error / Warning / Information depending on the character)\r\n\r\nDetects invisible or visually deceptive Unicode characters (\"gremlins\") such as\r\nzero-width spaces, non-breaking spaces, bidirectional overrides, and curly quotes\r\n(`‘ ’ “ ”`). These characters are nearly impossible to spot in an editor but can\r\nintroduce subtle bugs or security issues.\r\n\r\n```powershell\r\n# This will trigger the rule (curly quotes instead of straight ASCII quotes):\r\nWrite-Host “Hello, World!”\r\n```\r\n\r\n**Why it matters:** Gremlin characters can silently break string comparisons,\r\nsneak past code review, or be used to disguise malicious code. Surfacing them at\r\nanalysis time makes the invisible visible.\r\n\r\n\u003e [!IMPORTANT]\r\n\u003e **File encoding affects detection.** The bytes a parser sees depend on how the\r\n\u003e file is decoded, and that default differs by PowerShell edition:\r\n\u003e\r\n\u003e - **PowerShell 7+** reads files without a byte-order mark (BOM) as **UTF-8**.\r\n\u003e - **Windows PowerShell 5.1** reads BOM-less files using the system **ANSI code\r\n\u003e   page** (e.g. Windows-1252).\r\n\u003e\r\n\u003e A multi-byte UTF-8 gremlin (for example an en dash `U+2013`, stored as\r\n\u003e `E2 80 93`) is decoded correctly under PowerShell 7, but under 5.1 those bytes\r\n\u003e are interpreted as separate Windows-1252 characters — so the rule may report a\r\n\u003e different code point, or miss it entirely. **Save files as UTF-8 with a BOM** to\r\n\u003e get consistent results across both editions.\r\n\r\n## Examples\r\n\r\n### Running a Single Rule\r\n\r\n```powershell\r\n# Install and import\r\nInstall-PSResource GoodEnoughRules\r\n$module = Import-Module GoodEnoughRules -PassThru\r\n# Get the path the psm1\r\n$modulePath = Join-Path $module.ModuleBase $module.RootModule\r\n# Run against a folder\r\nInvoke-ScriptAnalyzer -CustomRulePath $modulePath -IncludeRule 'Measure-InvokeWebRequestWithoutBasic' -Path '.\\scripts\\'\r\n```\r\n\r\n## Walk Through\r\n\r\n\u003e [!TIP]\r\n\u003e Use a \"proxy module\" to load all your different custom rules and check that into your repository. This helps you avoid having to hardcode to a specific module path.\r\n\r\n1. Install the module.\r\n2. Create a custom rule file: `PSScriptAnalyzerRules.psm1`\r\n\r\n    ```pwsh\r\n    # Proxy Module example\r\n    $rules = Import-Module -Name 'GoodEnoughRules' -PassThru\r\n    Export-ModuleMember -Function @($rules.ExportedCommands.Keys)\r\n    ```\r\n\r\n3. Import it into your PSScriptAnalyzer config: `PSScriptAnalyzerSettings.psd1`\r\n\r\n    ```pwsh\r\n    @{\r\n        CustomRulePath      = @(\r\n            '.\\PSScriptAnalyzerRules.psm1'\r\n        )\r\n\r\n        IncludeDefaultRules = $true\r\n\r\n        IncludeRules        = @(\r\n            # Default rules\r\n            'PSAvoidDefaultValueForMandatoryParameter'\r\n            'PSAvoidDefaultValueSwitchParameter'\r\n\r\n            # Custom rules\r\n            'Measure-*'\r\n        )\r\n    }\r\n    ```\r\n\r\nIf you're interested in learning more about the \"Proxy Module\" concept, see\r\n[Sharing Your Custom PSScriptAnalyzer Rules][sharing-custom-psscriptanalyzer-rules]\r\n\r\n## Using PSDepend\r\n\r\nThis module depends on `PSScriptAnalyzer` which means that it will install it\r\nif's not available. If you have different required versions in your PSDepend\r\nconfiguration that can cause conflict. I will try to avoid that by only\r\nrequiring a minimum version.\r\n\r\n[psgallery-downloads-badge]: https://img.shields.io/powershellgallery/dt/goodenoughrules\r\n[psgallery-version-badge]: https://img.shields.io/powershellgallery/v/GoodEnoughRules\r\n[build-badge]: https://img.shields.io/github/actions/workflow/status/HeyItsGilbert/GoodEnoughRules/.github/workflows/publish.yaml?branch=main\r\n[platform-badge]: https://img.shields.io/powershellgallery/p/GoodEnoughRules\r\n[psgallery]: https://www.powershellgallery.com/packages/GoodEnoughRules\r\n[sharing-custom-psscriptanalyzer-rules]: https://gilbertsanchez.com/posts/sharing-custom-psscriptanalyzer-rules/\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheyitsgilbert%2Fgoodenoughrules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheyitsgilbert%2Fgoodenoughrules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheyitsgilbert%2Fgoodenoughrules/lists"}