Skip to content

Add Optional PSUseConstrainedLanguageMode rule#2165

Open
joshcorr wants to merge 13 commits intoPowerShell:mainfrom
joshcorr:addCLMRules
Open

Add Optional PSUseConstrainedLanguageMode rule#2165
joshcorr wants to merge 13 commits intoPowerShell:mainfrom
joshcorr:addCLMRules

Conversation

@joshcorr
Copy link

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.

Comment on lines +66 to +69
/// When true, ignores script signatures and runs all CLM checks regardless of signature status.
/// When false (default), scripts with valid signatures are treated as having elevated permissions
/// and only critical checks (dot-sourcing, parameter types, manifests) are performed.
/// Set to true to enforce full CLM compliance even for signed scripts.
Comment on lines +594 to +598
// Check if the variable was declared with a type constraint elsewhere
// Look for assignment statements with type constraints
var assignmentWithType = FindTypedAssignment(varExpr);
if (assignmentWithType != null)
{
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
Comment on lines +342 to +343
Context "Informational severity" {
It "Should have Information severity" {
<value>Module manifest field '{0}' uses wildcard ('*') which is not recommended for Constrained Language Mode. Explicitly list exported items instead.</value>
</data>
<data name="UseConstrainedLanguageModeScriptModuleError" xml:space="preserve">
<value>Module manifest field '{0}' contains script file '{1}' (.ps1). Use binary modules (.psm1 or .dll) instead for Constrained Language Mode compatibility.</value>

Use `New-Object PSObject` with `Add-Member` or hashtables instead of classes.

**Important**: `[PSCustomObject]@{}` syntax is NOT allowed in CLM because it uses type casting.
@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.

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.

3 participants