Compartir a través de


UseConstrainedLanguageMode

Nivel de gravedad: Advertencia

Descripción

Esta regla identifica patrones PowerShell que están restringidos o no están permitidos en el Modo de Lenguaje Restringido (CLM).

El Modo de Lenguaje Restringido es una característica de seguridad de PowerShell que restringe:

  • Tipos .NET que pueden usarse
  • Objetos COM que pueden ser instanciados
  • Comandos que pueden ejecutarse
  • Características del lenguaje que pueden utilizarse

La CLM se utiliza comúnmente en:

  • Entornos de Control de Aplicaciones (Control de Aplicaciones para Negocios, AppLocker)
  • Endpoints de Administración Suficiente (JEA)
  • Entornos seguros que requieren restricciones adicionales en PowerShell

Los scripts firmados digitalmente de editores de confianza se ejecutan en Modo Completo de Lenguaje (FLM) incluso en entornos CLM. La regla detecta bloques de firma (# SIG # Begin signature block) y ajusta las comprobaciones en consecuencia. La mayoría de las restricciones no se aplican a los scripts firmados, pero siempre se aplican ciertas comprobaciones (dot-sourcing, tipos de parámetros, mejores prácticas de manifiesto).

Importante

La regla realiza una comprobación sencilla de texto para bloques de firma y NO valida la autenticidad de la firma ni la confianza en el certificado. La validación real de la firma la realiza PowerShell en tiempo de ejecución.

Restricciones de modos de lenguaje restringidos

Scripts sin signo (Comprobación completa de CLM)

Los siguientes se marcan para los scripts sin firmar:

  1. Tipo de Adición - No se permite la compilación de código
  2. Objetos COM no permitidos - Solo se permiten Scripting.Dictionary, Scripting.FileSystemObject, VBScript.RegExp
  3. Tipos .NET prohibidos - Solo ~70 tipos permitidos (cadena, int, tabla hash, pscredential, etc.)
  4. Restricciones de tipo - Sobre parámetros y variables
  5. Expresiones de tipo - Referencias de tipo estáticas como [Type]::Method()
  6. Tipos de Cast - Conversión a tipos no permitidos
  7. Invocaciones de miembros - Métodos/propiedades sobre tipos no permitidos
  8. Clases - classPowerShell palabra clave no permitida
  9. XAML/WPF - No permitido
  10. Invocar-Expresión - Restringida
  11. Dot-Source : puede estar restringido dependiendo del archivo que se obtenga
  12. Comodines del Manifesto de Módulos - No se recomienda exportar comodines
  13. Archivos de manifiestos de .ps1 módulo - No se permiten módulos de script que terminan en .ps1

Siempre se hace cumplir, incluso para guiones firmados

Scripts con signo (Verificación selectiva)

Para scripts con bloques de firma, solo se comprueban estos:

  • Dot-sourcing
  • Restricciones de tipo de parámetro
  • Comodines del manifiesto del módulo (archivos .psd1)
  • Módulos de script de manifiestos (archivos .psd1)

Configuración

Configuración básica

@{
    Rules = @{
        PSUseConstrainedLanguageMode = @{
            Enable = $true
        }
    }
}

Parámetros

Habilitar: bool (el valor predeterminado es $false)

Habilite o deshabilite la regla durante la invocación de ScriptAnalyzer. Esta regla está deshabilitada por defecto porque no todos los scripts necesitan compatibilidad con CLM.

IgnoreSignatures: bool (El valor por defecto es $false)

Comportamiento de detección de firma de control:

  • $false (por defecto): Detectar firmas automáticamente. Los scripts firmados reciben verificación selectiva, los no firmados reciben comprobación completa.
  • $true: Omitir detección de firma. TODOS los scripts reciben una verificación completa de CLM independientemente del estado de la firma.
@{
    Rules = @{
        PSUseConstrainedLanguageMode = @{
            Enable = $true
            IgnoreSignatures = $true  # Enforce full CLM compliance for all scripts
        }
    }
}

Utilice IgnoreSignatures = $true si:

  • Auditoría de scripts firmados para asegurar la compatibilidad total con CLM
  • Preparación de scripts para entornos no confiables
  • Aplicación estricta del cumplimiento de CLM a nivel organizacional
  • Desarrollo/pruebas para ver todos los posibles problemas

Solución

Sustituir Add-Type

Utiliza cmdlets permitidos o ensamblajes de precompilación.

Reemplazar objetos COM no permitidos

Utiliza solo objetos COM permitidos (Scripting.Dictionary, Scripting.FileSystemObject, VBScript.RegExp) o los cmdlets de PowerShell.

Reemplazar tipos no permitidos

Utiliza aceleradores de tipos permitidos ([string], [int], [hashtable], etc.) o cmdlets permitidos en lugar de tipos .NET prohibidos.

Reemplazar las clases PowerShell

Úsalo New-Object PSObject con Add-Member o hashtables en lugar de clases.

Importante

[PSCustomObject]@{} la sintaxis NO está permitida en CLM porque utiliza casting de tipos.

Evita XAML

No uses WPF/XAML en scripts compatibles con CLM.

Sustituir Invoke-Expression

Utiliza ejecuciones directas (&) o alternativas más seguras.

Sustituir Dot-Sourcing

Utiliza módulos con Import-Module en lugar de usar dot sourcing cuando sea posible.

Manifiestos de módulos de corrección

  • Sustituye las exportaciones comodines (*) por listas explícitas.
  • Úsase .psm1 o .dll en lugar de .ps1 para RootModule/NestedModules.
  • No use ScriptsToProcess. Estos scripts se cargan en el ámbito del llamador y se bloquean.

Ejemplos

Ejemplo 1: Add-Type

Incorrecto

Add-Type -TypeDefinition @"
    public class Helper {
        public static string DoWork() { return "Done"; }
    }
"@

Corregir

 # Code sign your scripts/modules using proper signing tools
 #   (for example, Set-AuthenticodeSignature or external signing processes)
 # Use allowed cmdlets instead of Add-Type-defined types where possible
 # Or pre-compile, sign, and load the assembly (for example, via Add-Type -Path)

Ejemplo 2: Objetos COM

Incorrecto

$excel = New-Object -ComObject Excel.Application

Corregir

# Use allowed COM object
$dict = New-Object -ComObject Scripting.Dictionary

# Or use PowerShell cmdlets
Import-Excel -Path $file  # From ImportExcel module

Ejemplo 3: Tipos prohibidos

Incorrecto

# Type constraint and member invocation flagged
function Download-File {
    param([System.Net.WebClient]$Client)
    $Client.DownloadString($url)
}

# Type cast and method call flagged
[System.Net.WebClient]$client = New-Object System.Net.WebClient
$data = $client.DownloadData($url)

Corregir

# Use allowed cmdlets
function Download-File {
    param([string]$Url)
    Invoke-WebRequest -Uri $Url
}

# Use allowed types
function Process-Text {
    param([string]$Text)
    $upper = $Text.ToUpper()  # String methods are allowed
}

Ejemplo 4: Clases PowerShell

Incorrecto

class MyClass {
    [string]$Name

    [string]GetInfo() {
        return $this.Name
    }
}

# Also wrong - uses type cast
$obj = [PSCustomObject]@{
    Name = "Test"
}

Corregir

# Option 1: New-Object PSObject with Add-Member
$obj = New-Object PSObject -Property @{
    Name = "Test"
}

$obj | Add-Member -MemberType ScriptMethod -Name GetInfo -Value {
    return $this.Name
}

Add-Member -InputObject $obj -NotePropertyMembers @{"Number" = 42}

# Option 2: Hashtable
$obj = @{
    Name = "Test"
    Number = 42
}

Ejemplo 5: Manifiestos de módulos

Incorrecto

@{
    ModuleVersion = '1.0.0'
    RootModule = 'MyModule.ps1'        # .ps1 not recommended
    FunctionsToExport = '*'             # Wildcard not recommended
    CmdletsToExport = '*'
}

Corregir

@{
    ModuleVersion = '1.0.0'
    RootModule = 'MyModule.psm1'       # Use .psm1 or .dll
    FunctionsToExport = @(              # Explicit list
        'Get-MyFunction'
        'Set-MyFunction'
    )
    CmdletsToExport = @()
}

Ejemplo 6: Tipos de Array

Incorrecto

# Disallowed type in array
param([System.Net.WebClient[]]$Clients)

Corregir

# Allowed types in arrays are fine
param([string[]]$Names)
param([int[]]$Numbers)
param([hashtable[]]$Configuration)

Restricciones detalladas

1. Add-Type

Add-Type permite compilar código C# arbitrario y no está permitido en CLM.

Aplicado para: Solo guiones sin firmar

2. COM Objetos

Solo se permiten tres objetos COM:

  • Scripting.Dictionary
  • Scripting.FileSystemObject
  • VBScript.RegExp

Todos los demás (Excel.Application, WScript.Shell, etc.) están marcados.

Aplicado para: Solo guiones sin firmar

3. Tipos .NET

Solo permiten ~70 tipos, incluyendo:

  • Primitivas: string, int, bool, byte, char, datetime, decimal, double, etc.
  • Colecciones: hashtable, array, arraylist
  • PowerShell: pscredential, psobject, securestring
  • Servicios: regex, guid, version, uri, xml
  • Arrays: string[], int[][], etc. (array de cualquier tipo permitido)

La regla comprueba el uso de tipos en:

  • Restricciones de tipo de parámetro (siempre aplicadas, incluso para scripts con signo)
  • Restricciones de tipo de variable
  • New-Object -TypeName
  • Expresiones de tipo ([Type]::Method())
  • Tipos de fundición ([Type]$variable)
  • Invocaciones de miembros en variables tipadas

Aplicado para: Restricciones de parámetros siempre; otros solo sin firmar

4. Clases PowerShell

La class palabra clave no está permitida. Úsalo New-Object PSObject con Add-Member o hashtables.

Nota:[PSCustomObject]@{} tampoco está permitido porque utiliza tipcasting.

Aplicado para: Solo guiones sin firmar

5. XAML/WPF

XAML y WPF no están permitidos en CLM.

Aplicado para: Solo guiones sin firmar

6. Invoke-Expression

Invoke-Expression está restringido en CLM.

Aplicado para: Solo guiones sin firmar

7. Dot-Sourcing

El dot-sourcing (. $PSScriptRoot\script.ps1) puede estar restringido dependiendo de la ubicación de la fuente.

Aplicado para: TODOS los guiones (sin firmar ni firmar)

8. Mejores prácticas para el manifiesto de módulos

Exportaciones comodines

No usar * en: FunctionsToExport, CmdletsToExport, AliasesToExport, VariablesToExport

Utiliza listas explícitas para seguridad y claridad.

Aplicado para: TODOS los archivos .psd1 (sin firmar ni firmar)

Archivos de módulos de script

No uses .ps1 archivos en: RootModule, ModuleToProcess, NestedModules

Úsalos .psm1 (módulos script) o .dll (módulos binarios) para mejorar el rendimiento y la compatibilidad.

Aplicado para: TODOS los archivos .psd1 (sin firmar ni firmar)

Más Información