Skip to content

Add Optional PSUseConstrainedLanguageMode rule#2165

Merged
andyleejordan merged 20 commits intoPowerShell:mainfrom
joshcorr:addCLMRules
Mar 20, 2026
Merged

Add Optional PSUseConstrainedLanguageMode rule#2165
andyleejordan merged 20 commits intoPowerShell:mainfrom
joshcorr:addCLMRules

Conversation

@joshcorr
Copy link
Contributor

PR Summary

This PR adds a new rule PSUseConstrainedLanguageMode that identifies PowerShell patterns incompatible with Constrained Language Mode, helping developers ensure scripts work in restricted environments. This rule is a Warning, but is optional and not enabled by default.

New files:
Rules/UseConstrainedLanguageMode.cs - Implements 14 CLM restriction checks
Tests/Rules/UseConstrainedLanguageMode.tests.ps1 - Adds 46 comprehensive tests
docs/Rules/UseConstrainedLanguageMode.md - Provides complete user documentation

Modified files;

Rules/strings.resx - Adds 16 new diagnostic message strings

Features
Detects CLM Violations:

  • Add-Type usage (code compilation)
  • Disallowed COM objects (only allows Scripting.Dictionary, Scripting.FileSystemObject, VBScript.RegExp)
  • Disallowed .NET types (validates ~70 allowed types including primitives, collections, PowerShell types)
  • PowerShell classes (class keyword)
  • XAML/WPF usage
  • Invoke-Expression usage
  • Dot-sourcing patterns
  • Type constraints, expressions, and casts
  • Member invocations on disallowed types
  • Module manifest wildcards and .ps1 references

Signature Awareness:

  • Detects signature blocks (# SIG # Begin signature block)
  • Applies selective checking to signed scripts (dot-sourcing, parameter types, manifests only)
  • Applies full checking to unsigned scripts

Array Type Support:

  • Handles array notation correctly ([string[]], [int[][]])
  • Strips brackets and validates base types

Configuration:

  • IgnoreSignatures property (default: false) bypasses signature detection and enforces full CLM compliance for all scripts

Testing:
image

PR Checklist

Copilot AI review requested due to automatic review settings March 17, 2026 15:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new optional ScriptAnalyzer rule (PSUseConstrainedLanguageMode) to detect PowerShell patterns that are incompatible with Constrained Language Mode (CLM), along with tests and documentation so users can opt into CLM-focused linting.

Changes:

  • Added UseConstrainedLanguageMode rule implementation to detect multiple CLM-incompatible patterns, with special handling for signature blocks.
  • Added a comprehensive Pester test suite for the new rule.
  • Added end-user documentation and new localized resource strings for diagnostics.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
Rules/UseConstrainedLanguageMode.cs Implements the new rule logic (CLM checks, signature-block detection, manifest checks).
Tests/Rules/UseConstrainedLanguageMode.tests.ps1 Adds tests covering the new rule’s detections and signature behavior.
docs/Rules/UseConstrainedLanguageMode.md Documents what the rule flags, signed vs unsigned behavior, and configuration.
Rules/Strings.resx Adds diagnostic strings used by the new rule (and updates file header/encoding).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@liamjpeters
Copy link
Contributor

👋 @joshcorr,

I wonder if UseConstrainedLanguageMode is the best name for this. The rule isn't checking if you're using/enabling constrained language mode, but rather that you're conforming to it's restrictions at design-time.

Perhaps something like ConformToConstrainedLanguageMode could be more on the money? One to consider.

@joshcorr
Copy link
Contributor Author

Hi @liamjpeters thanks for the feedback. I named the rule to conform to the existing naming structure Use.. over some of the other leading verbs I found in the project (Avoid, Possible, etc). I do see this rule trying to check for implementation of language specific features (i.e. will this script use constrained language mode correctly), so the name doesn't feel that odd to me, but I see your point. Will wait to see if Andy or others have a strong opinion on the naming.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please tidy away the whitespace diff please? might be easiest to just copy paste the first 58 lines from main over this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit.

@bergmeister
Copy link
Collaborator

bergmeister commented Mar 18, 2026

Wow, what a great idea and implementation @joshcorr Build seems to be currently broken, if you could fix that would be great (maybe it's simply due to that whitespace diff in the xml file, msbuild can be picky at times.
Please bear with us as it's a big change to review but very happy to have it :-)

@bergmeister bergmeister requested a review from Copilot March 18, 2026 19:45
}

// Only flag if COM object name was found AND it's not in the allowed list
if (!string.IsNullOrWhiteSpace(comObjectValue) && !AllowedComObjects.Contains(comObjectValue))
Copy link
Collaborator

@bergmeister bergmeister Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor but wouldn't it reader better as !comObjectValue.IsNullOrWhiteSpace() since comObjectValue is already typed as string? similar a bit below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked into this and since the IsNullOrWhiteSpace() is a public static method on the string class, it can't be called from a string object., but rather from the class.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, it's been clearly some time ago that I actively wrote a lot of C#, would have thought hoped that .NET would've improved on those things but seems not

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new optional ScriptAnalyzer rule to warn about PowerShell constructs that are incompatible with Constrained Language Mode (CLM), along with accompanying tests and documentation.

Changes:

  • Introduces PSUseConstrainedLanguageMode rule implementation (signature-aware + CLM pattern checks).
  • Adds a comprehensive Pester test suite for the rule.
  • Adds rule documentation and localized diagnostic strings.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Rules/UseConstrainedLanguageMode.cs Implements the new CLM compatibility rule (AST checks + signature-aware behavior + caching).
Tests/Rules/UseConstrainedLanguageMode.tests.ps1 Adds Pester coverage for the new rule, including signed/unsigned scenarios and performance-related validation.
docs/Rules/UseConstrainedLanguageMode.md Documents rule purpose, configuration, and remediation guidance.
docs/Rules/README.md Adds the new rule to the rules index table.
Rules/Strings.resx Adds localized strings for rule name/description and diagnostic messages.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +726 to +727
// Find all assignment statements in this scope
var assignments = scope.FindAll(testAst => testAst is AssignmentStatementAst, true);
@bergmeister
Copy link
Collaborator

bergmeister commented Mar 19, 2026

@joshcorr We merged a few other PRs that now caused a merge conflict here, can you pull latest of main into your branch and resolve conflict please?
I also kicked off build, which is working now but one of your new tests is failing, please have a look at it as well please: https://github.com/PowerShell/PSScriptAnalyzer/actions/runs/23281623145/job/67789974715?pr=2165#step:7:93
image

Thanks :-)

Copy link
Member

@andyleejordan andyleejordan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @joshcorr, hope the session goes well. I'll get this out!

@andyleejordan andyleejordan merged commit 6cfc260 into PowerShell:main Mar 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants