This document outlines the PowerShell Script Analyzer rules, custom rule implementations, and github.com security configurations that ensure code quality, consistency, and security across the evergreen-apps repository.
- PowerShell Script Analyzer Configuration
- Custom Rules
- IDE Integration
- CI/CD Security and Validation
- Branch Protection Rules
- File Encoding and Format Standards
File: .rules/PSScriptAnalyzerSettings.psd1
@{
CustomRulePath = @(
".rules/LowercaseKeyword.psm1"
)
IncludeDefaultRules = $true
Severity = @("Error", "Warning")
IncludeRules = @(
"Measure-LowercaseKeyword"
)
}-
CustomRulePath: Specifies the path to custom PowerShell Script Analyzer rules implemented in the repository
- Includes LowercaseKeyword.psm1 for code style enforcement
-
IncludeDefaultRules: Set to
$true- Enables all built-in PSScriptAnalyzer rules (e.g., PSAvoidUsingCmdletAliases, PSAvoidUsingPositionalParameters, PSAvoidUsingInvokeExpression)
- Provides comprehensive code quality checks beyond custom rules
-
Severity: Set to
@("Error", "Warning")- Analyzer reports both errors and warnings
- Both severity levels must be addressed in code reviews
-
IncludeRules: Explicitly enables the
Measure-LowercaseKeywordcustom rule- Only listed custom rules are active; others must be explicitly required in this configuration
File: .rules/LowercaseKeyword.psm1
Ensures PowerShell keywords and constants use lowercase formatting for consistency and adherence to PowerShell best practices.
Checks the following elements:
Keywords:
- Control flow:
function,if,elseif,else,switch,foreach,for,while,do,until,try,catch,finally,throw,trap - Function-related:
param,begin,process,end,dynamicparam - Other:
return,in,break,continue,exit,class,enum,using,namespace,data
Constants:
- Boolean:
$true,$false - Null:
$null
Keyword 'KEYWORD' should be lowercase ('keyword').
Constant 'CONSTANT' should be lowercase ('constant').
# VIOLATION: Keywords not in lowercase
Function Get-Data { } # Should be: function Get-Data { }
IF ($condition) # Should be: if ($condition)
$value = $TRUE # Should be: $value = $trueWarning - Code style violation that should be corrected during review but doesn't prevent deployment.
- Uses token-based analysis for accurate detection
- Avoids duplicate reporting of the same token at the same location
- Implements case-sensitive comparison (
-cne) to distinguish between cases - Handles parse errors gracefully without stopping analysis
File: .vscode/settings.json
| Setting | Value | Purpose |
|---|---|---|
files.eol |
\n |
Enforces Unix-style line endings (LF) for all files in the repository |
powershell.scriptAnalysis.settingsPath |
.rules/PSScriptAnalyzerSettings.psd1 |
Points PowerShell extension to custom analyzer settings |
powershell.scriptAnalysis.enable |
true |
Activates real-time script analysis in the editor |
- Consistency: All developers using VS Code see the same analysis rules
- Real-time Feedback: Issues are flagged during development, not just in CI/CD
- Line Ending Standardization: Prevents CRLF/LF inconsistencies across platforms
- Immediate Education: Developers learn correct patterns as they code
File: .github/workflows/validate.yml
- Push to non-main branches when Apps or Manifests directories change
- Pull request to main branch when Apps or Manifests directories change
- Manual trigger via
workflow_dispatch
permissions:
contents: read # Read-only access to code
security-events: write # Write SARIF scan results
actions: read # Read workflow status (private repos)Purpose: Runs comprehensive PowerShell code analysis
Configuration:
- name: 'Analyse PowerShell'
uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f
with:
path: "./Apps"
recurse: true
settings: ".rules/PSScriptAnalyzerSettings.psd1"
output: results.sarifWhat it checks:
- Applies all built-in PSScriptAnalyzer rules
- Applies custom rules (LowercaseKeyword)
- Recursively analyzes all scripts in the Apps directory
- Generates SARIF (Static Analysis Results Interchange Format) output for GitHub security tab
SARIF Upload:
- Results are uploaded to GitHub Code Scanning
- Available in Security > Code scanning alerts
- Issues appear in PR reviews automatically
Failure Behavior:
- Analysis failures block the entire validation workflow
- Pull requests cannot be merged until analysis passes
Dependencies: Requires successful completion of psscriptanalyzer job
Validations performed:
✓ Apps directory must contain ONLY .ps1 files
✓ Manifests directory must contain ONLY .json files
✓ No empty files allowed in Apps or Manifests
✓ Reports all empty files before failing
✓ All JSON files in Manifests must be valid JSON
✓ Uses jq to verify JSON syntax
✓ Reports which files have invalid JSON
PowerShell Files:
✓ All .ps1 files must be UTF-8 or ASCII encoded
✗ Rejects any other encoding (e.g., UTF-16, UTF-32, ISO-8859-1)
JSON Files:
✓ All .json files must be UTF-8 or ASCII encoded
✗ Rejects any other encoding
Any validation failure will:
- Display detailed error message listing problematic files
- Block workflow completion
- Prevent merge of pull request
- Appear as failed check on PR
Based on the workflow triggers defined in .github/workflows/validate.yml and .github/workflows/release.yml, the following branch protection rules are recommended and implemented:
| Requirement | Status | Details |
|---|---|---|
| Require status checks to pass before merging | ✅ Enabled | psscriptanalyzer job must pass |
| Require status checks to pass before merging | ✅ Enabled | validate-json job must pass |
| Require pull request reviews | ✅ Enabled | Recommended: at least 1 approved review |
| Dismiss stale pull request approvals | ✅ Enabled | Approvals reset when code changes |
| Require code owners approval | Implement CODEOWNERS file if needed |
| Restriction | Status |
|---|---|
| Allow force pushes | ❌ Disabled |
| Allow deletions | ❌ Disabled |
| Require branches to be up to date before merging | ✅ Enabled |
| Require conversation resolution before merging | ✅ Enabled |
- Require linear history: Enforces a clean Git history
- Allow merge commits: Controlled via GitHub settings
- Allow squash merging: Recommended for clean commits
- Allow rebase merging: Recommended to preserve history
The validation workflow only triggers when these paths change:
- 'Apps/**'
- 'Manifests/**'
This means:
- Changes to configuration files (
.rules/,.github/,.vscode/) trigger validation - Documentation changes alone do not block merges
- Maintainers can update workflows without strict validation
File: .gitattributes
* -text- Files are stored as-is without automatic line ending conversion
- Manual LF normalization via
.vscode/settings.json
*.ps1 text
*.psm1 text
*.psd1 text- All PowerShell files marked as text
- Git properly handles line-ending diffs
*.json text
*.xml text- JSON and XML files marked as text
- Enables proper Git diffing and merging
*.ai binary
*.bmp binary
*.eps binary
*.gif binary
# ... (all graphics and binary formats)- Prevents Git from attempting to merge binary files
- Improves merge conflict handling
- Standard: Unix-style LF (
\n) - Enforcement: VS Code
.vscode/settings.jsonenforces this - Validation: CI/CD doesn't explicitly validate but expects UTF-8 compliance
- Standard: UTF-8 (with UTF-8 BOM or no BOM)
- Accepted: Also accepts ASCII (subset of UTF-8)
- Validation: CI/CD workflow explicitly validates all files
- Rejection: Rejects UTF-16, UTF-32, ISO-8859-1, and other encodings
- PowerShell Scripts: Must be
.ps1(not.txtor other extensions) - Manifests: Must be
.json(not.json5or other formats) - No empty files: All files must have content
- IDE-level analysis: Developers see issues before commit
- Pre-commit validation: Can be enhanced with pre-commit hooks
- CI/CD validation: GitHub Actions workflow runs on every PR
- SARIF reporting: Security findings uploaded to GitHub Security tab
- Workflows use least-privilege permissions
contents: readonly for code scanningsecurity-events: writefor uploading analysis results- No unnecessary elevated permissions
- Main branch has force-push protection
- Direct pushes to main disabled (require PR)
- Status checks prevent merge of flagged code
- SARIF results create audit trail of security checks
- UTF-8 validation prevents encoding-based exploits
- Consistent line endings reduce diff confusion
- Binary file protection prevents accidental commits of machine-dependent data
- Edit custom rule file: Modify
.rules/LowercaseKeyword.psm1or.rules/PascalCase.psm1 - Update settings file: Add/remove rules in
.rules/PSScriptAnalyzerSettings.psd1 - Test locally: Run analyzer with
Invoke-ScriptAnalyzer - Update documentation: Modify this file
- Create PR: Changes to analyzer rules go through normal PR workflow
- Edit workflow file: Modify
.github/workflows/validate.yml - Test in PR: Workflow runs on PR creation automatically
- Monitor job output: Check GitHub Actions logs for any issues
- Merge when validated: Approved changes become effective on main branch
To disable the Measure-PascalCase rule (currently not enabled):
- Remove or comment out from
PSScriptAnalyzerSettings.psd1:
# IncludeRules = @(
# "Measure-PascalCase"
# )- Or add to exclusion list (if supported):
ExcludeRules = @("Measure-PascalCase")- Microsoft.PowerShell.ScriptAnalyzer - Official analyzer repository
- PowerShell Best Practices - Microsoft's PowerShell style guide
- GitHub Code Scanning - Security analysis documentation
- SARIF Format - Static Analysis Results Interchange Format
Last Updated: February 5, 2026
{ "files.eol": "\n", "powershell.scriptAnalysis.settingsPath": ".rules/PSScriptAnalyzerSettings.psd1", "powershell.scriptAnalysis.enable": true }