diff --git a/CHANGELOG.md b/CHANGELOG.md index 44c2a29707..56bf3fd4ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ See [upgrade notes][1] for helpful information when upgrading from previous versions. - [1]: https://microsoft.github.io/PSRule/latest/upgrade-notes/ + [1]: https://aka.ms/ps-rule/upgrade ## Current release diff --git a/docs/CHANGELOG-v2.md b/docs/CHANGELOG-v2.md index 7d5c1a8b84..4b21c6e985 100644 --- a/docs/CHANGELOG-v2.md +++ b/docs/CHANGELOG-v2.md @@ -6,14 +6,14 @@ discussion: false See [upgrade notes][1] for helpful information when upgrading from previous versions. - [1]: https://microsoft.github.io/PSRule/latest/upgrade-notes/ + [1]: https://aka.ms/ps-rule/upgrade **Important notes**: - Several properties of rule and language block elements will be removed from v3. See [deprecations][2] for details. - [2]: https://microsoft.github.io/PSRule/latest/deprecations/#deprecations-for-v3 + [2]: https://aka.ms/ps-rule/deprecations#deprecations-for-v3 **Experimental features**: @@ -33,6 +33,12 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers What's changed since v2.7.0: - General improvements: + - **Important change**: Replaced `SuppressedRuleWarning` execution option with `RuleSuppressed` by @BernieWhite. + [#1456](https://github.com/microsoft/PSRule/issues/1456) + - Improved options for output of suppressed rules with `RuleSuppressed` option. + - Deprecated `SuppressedRuleWarning` option, which will be removed in v3. + - Added support for logging excluded rules by @BernieWhite. + [#1432](https://github.com/microsoft/PSRule/issues/1432) - Added additional options to schema for PSRule for Azure by @BernieWhite. [#1446](https://github.com/microsoft/PSRule/issues/1446) - Improved error message for failing to read options file by @BernieWhite. diff --git a/docs/commands/PSRule/en-US/New-PSRuleOption.md b/docs/commands/PSRule/en-US/New-PSRuleOption.md index fa3c24db22..98534106da 100644 --- a/docs/commands/PSRule/en-US/New-PSRuleOption.md +++ b/docs/commands/PSRule/en-US/New-PSRuleOption.md @@ -22,18 +22,19 @@ New-PSRuleOption [[-Path] ] [-Configuration ] [-BindingNameSeparator ] [-BindingPreferTargetInfo ] [-TargetName ] [-TargetType ] [-BindingUseQualifiedName ] [-Convention ] [-AliasReferenceWarning ] [-DuplicateResourceId ] - [-InconclusiveWarning ] [-NotProcessedWarning ] [-SuppressedRuleWarning ] - [-InvariantCultureWarning ] [-InitialSessionState ] [-IncludeModule ] - [-IncludePath ] [-Format ] [-InputIgnoreGitPath ] - [-InputIgnoreRepositoryCommon ] [-InputIgnoreObjectSource ] - [-InputIgnoreUnchangedPath ] [-ObjectPath ] [-InputTargetType ] - [-InputPathIgnore ] [-LoggingLimitDebug ] [-LoggingLimitVerbose ] - [-LoggingRuleFail ] [-LoggingRulePass ] [-OutputAs ] - [-OutputBanner ] [-OutputCulture ] [-OutputEncoding ] - [-OutputFooter ] [-OutputFormat ] [-OutputJobSummaryPath ] - [-OutputJsonIndent ] [-OutputOutcome ] [-OutputPath ] - [-OutputSarifProblemsOnly ] [-OutputStyle ] [-RepositoryBaseRef ] - [-RepositoryUrl ] [-RuleIncludeLocal ] [] + [-InconclusiveWarning ] [-InvariantCultureWarning ] [-InitialSessionState ] + [-NotProcessedWarning ] [-SuppressedRuleWarning ] + [-SuppressionGroupExpired ] [-ExecutionRuleExcluded ] + [-ExecutionRuleSuppressed ] [-IncludeModule ] [-IncludePath ] + [-Format ] [-InputIgnoreGitPath ] [-InputIgnoreRepositoryCommon ] + [-InputIgnoreObjectSource ] [-InputIgnoreUnchangedPath ] [-ObjectPath ] + [-InputTargetType ] [-InputPathIgnore ] [-LoggingLimitDebug ] + [-LoggingLimitVerbose ] [-LoggingRuleFail ] [-LoggingRulePass ] + [-OutputAs ] [-OutputBanner ] [-OutputCulture ] + [-OutputEncoding ] [-OutputFooter ] [-OutputFormat ] + [-OutputJobSummaryPath ] [-OutputJsonIndent ] [-OutputOutcome ] + [-OutputPath ] [-OutputSarifProblemsOnly ] [-OutputStyle ] + [-RepositoryBaseRef ] [-RepositoryUrl ] [-RuleIncludeLocal ] [] ``` ### FromOption @@ -45,18 +46,19 @@ New-PSRuleOption [-Option] [-Configuration ] [-BindingNameSeparator ] [-BindingPreferTargetInfo ] [-TargetName ] [-TargetType ] [-BindingUseQualifiedName ] [-Convention ] [-AliasReferenceWarning ] [-DuplicateResourceId ] - [-InconclusiveWarning ] [-NotProcessedWarning ] [-SuppressedRuleWarning ] - [-InvariantCultureWarning ] [-InitialSessionState ] [-IncludeModule ] - [-IncludePath ] [-Format ] [-InputIgnoreGitPath ] - [-InputIgnoreRepositoryCommon ] [-InputIgnoreObjectSource ] - [-InputIgnoreUnchangedPath ] [-ObjectPath ] [-InputTargetType ] - [-InputPathIgnore ] [-LoggingLimitDebug ] [-LoggingLimitVerbose ] - [-LoggingRuleFail ] [-LoggingRulePass ] [-OutputAs ] - [-OutputBanner ] [-OutputCulture ] [-OutputEncoding ] - [-OutputFooter ] [-OutputFormat ] [-OutputJobSummaryPath ] - [-OutputJsonIndent ] [-OutputOutcome ] [-OutputPath ] - [-OutputSarifProblemsOnly ] [-OutputStyle ] [-RepositoryBaseRef ] - [-RepositoryUrl ] [-RuleIncludeLocal ] [] + [-InconclusiveWarning ] [-InvariantCultureWarning ] [-InitialSessionState ] + [-NotProcessedWarning ] [-SuppressedRuleWarning ] + [-SuppressionGroupExpired ] [-ExecutionRuleExcluded ] + [-ExecutionRuleSuppressed ] [-IncludeModule ] [-IncludePath ] + [-Format ] [-InputIgnoreGitPath ] [-InputIgnoreRepositoryCommon ] + [-InputIgnoreObjectSource ] [-InputIgnoreUnchangedPath ] [-ObjectPath ] + [-InputTargetType ] [-InputPathIgnore ] [-LoggingLimitDebug ] + [-LoggingLimitVerbose ] [-LoggingRuleFail ] [-LoggingRulePass ] + [-OutputAs ] [-OutputBanner ] [-OutputCulture ] + [-OutputEncoding ] [-OutputFooter ] [-OutputFormat ] + [-OutputJobSummaryPath ] [-OutputJsonIndent ] [-OutputOutcome ] + [-OutputPath ] [-OutputSarifProblemsOnly ] [-OutputStyle ] + [-RepositoryBaseRef ] [-RepositoryUrl ] [-RuleIncludeLocal ] [] ``` ### FromDefault @@ -67,18 +69,19 @@ New-PSRuleOption [-Default] [-Configuration ] [-SuppressTar [-BindingField ] [-BindingNameSeparator ] [-BindingPreferTargetInfo ] [-TargetName ] [-TargetType ] [-BindingUseQualifiedName ] [-Convention ] [-AliasReferenceWarning ] [-DuplicateResourceId ] - [-InconclusiveWarning ] [-NotProcessedWarning ] [-SuppressedRuleWarning ] - [-InvariantCultureWarning ] [-InitialSessionState ] [-IncludeModule ] - [-IncludePath ] [-Format ] [-InputIgnoreGitPath ] - [-InputIgnoreRepositoryCommon ] [-InputIgnoreObjectSource ] - [-InputIgnoreUnchangedPath ] [-ObjectPath ] [-InputTargetType ] - [-InputPathIgnore ] [-LoggingLimitDebug ] [-LoggingLimitVerbose ] - [-LoggingRuleFail ] [-LoggingRulePass ] [-OutputAs ] - [-OutputBanner ] [-OutputCulture ] [-OutputEncoding ] - [-OutputFooter ] [-OutputFormat ] [-OutputJobSummaryPath ] - [-OutputJsonIndent ] [-OutputOutcome ] [-OutputPath ] - [-OutputSarifProblemsOnly ] [-OutputStyle ] [-RepositoryBaseRef ] - [-RepositoryUrl ] [-RuleIncludeLocal ] [] + [-InconclusiveWarning ] [-InvariantCultureWarning ] [-InitialSessionState ] + [-NotProcessedWarning ] [-SuppressedRuleWarning ] + [-SuppressionGroupExpired ] [-ExecutionRuleExcluded ] + [-ExecutionRuleSuppressed ] [-IncludeModule ] [-IncludePath ] + [-Format ] [-InputIgnoreGitPath ] [-InputIgnoreRepositoryCommon ] + [-InputIgnoreObjectSource ] [-InputIgnoreUnchangedPath ] [-ObjectPath ] + [-InputTargetType ] [-InputPathIgnore ] [-LoggingLimitDebug ] + [-LoggingLimitVerbose ] [-LoggingRuleFail ] [-LoggingRulePass ] + [-OutputAs ] [-OutputBanner ] [-OutputCulture ] + [-OutputEncoding ] [-OutputFooter ] [-OutputFormat ] + [-OutputJobSummaryPath ] [-OutputJsonIndent ] [-OutputOutcome ] + [-OutputPath ] [-OutputSarifProblemsOnly ] [-OutputStyle ] + [-RepositoryBaseRef ] [-RepositoryUrl ] [-RuleIncludeLocal ] [] ``` ## DESCRIPTION @@ -1037,6 +1040,57 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -ExecutionRuleExcluded + +Sets the option `Execution.RuleExcluded`. +The `Execution.RuleExcluded` option determines how to handle excluded rules. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ExecutionRuleSuppressed + +Sets the option `Execution.RuleSuppressed`. +The `Execution.RuleSuppressed` option determines how to handle suppressed rules. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SuppressionGroupExpired + +Sets the option `Execution.SuppressionGroupExpired`. +The `Execution.SuppressionGroupExpired` option determines how to handle expired suppression groups. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: ExecutionSuppressionGroupExpired + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). diff --git a/docs/commands/PSRule/en-US/Set-PSRuleOption.md b/docs/commands/PSRule/en-US/Set-PSRuleOption.md index 55cee7ad31..9e010f724d 100644 --- a/docs/commands/PSRule/en-US/Set-PSRuleOption.md +++ b/docs/commands/PSRule/en-US/Set-PSRuleOption.md @@ -19,18 +19,19 @@ Set-PSRuleOption [[-Path] ] [-Option ] [-PassThru] [-Force [-BindingPreferTargetInfo ] [-TargetName ] [-TargetType ] [-BindingUseQualifiedName ] [-Convention ] [-AliasReferenceWarning ] [-DuplicateResourceId ] [-InconclusiveWarning ] - [-NotProcessedWarning ] [-SuppressedRuleWarning ] [-InvariantCultureWarning ] - [-InitialSessionState ] [-IncludeModule ] [-IncludePath ] - [-Format ] [-InputIgnoreGitPath ] [-InputIgnoreObjectSource ] - [-InputIgnoreRepositoryCommon ] [-InputIgnoreUnchangedPath ] [-ObjectPath ] - [-InputPathIgnore ] [-InputTargetType ] [-LoggingLimitDebug ] - [-LoggingLimitVerbose ] [-LoggingRuleFail ] [-LoggingRulePass ] - [-OutputAs ] [-OutputBanner ] [-OutputCulture ] - [-OutputEncoding ] [-OutputFooter ] [-OutputFormat ] - [-OutputJobSummaryPath ] [-OutputJsonIndent ] [-OutputOutcome ] - [-OutputPath ] [-OutputSarifProblemsOnly ] [-OutputStyle ] - [-RepositoryBaseRef ] [-RepositoryUrl ] [-RuleIncludeLocal ] [-WhatIf] [-Confirm] - [] + [-InvariantCultureWarning ] [-InitialSessionState ] [-NotProcessedWarning ] + [-SuppressedRuleWarning ] [-SuppressionGroupExpired ] + [-ExecutionRuleExcluded ] [-ExecutionRuleSuppressed ] + [-IncludeModule ] [-IncludePath ] [-Format ] [-InputIgnoreGitPath ] + [-InputIgnoreObjectSource ] [-InputIgnoreRepositoryCommon ] + [-InputIgnoreUnchangedPath ] [-ObjectPath ] [-InputPathIgnore ] + [-InputTargetType ] [-LoggingLimitDebug ] [-LoggingLimitVerbose ] + [-LoggingRuleFail ] [-LoggingRulePass ] [-OutputAs ] + [-OutputBanner ] [-OutputCulture ] [-OutputEncoding ] + [-OutputFooter ] [-OutputFormat ] [-OutputJobSummaryPath ] + [-OutputJsonIndent ] [-OutputOutcome ] [-OutputPath ] + [-OutputSarifProblemsOnly ] [-OutputStyle ] [-RepositoryBaseRef ] + [-RepositoryUrl ] [-RuleIncludeLocal ] [-WhatIf] [-Confirm] [] ``` ## DESCRIPTION @@ -954,6 +955,57 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -ExecutionRuleExcluded + +Sets the option `Execution.RuleExcluded`. +The `Execution.RuleExcluded` option determines how to handle excluded rules. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ExecutionRuleSuppressed + +Sets the option `Execution.RuleSuppressed`. +The `Execution.RuleSuppressed` option determines how to handle suppressed rules. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SuppressionGroupExpired + +Sets the option `Execution.SuppressionGroupExpired`. +The `Execution.SuppressionGroupExpired` option determines how to handle expired suppression groups. + +```yaml +Type: ExecutionActionPreference +Parameter Sets: (All) +Aliases: ExecutionSuppressionGroupExpired + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). diff --git a/docs/concepts/PSRule/en-US/about_PSRule_Options.md b/docs/concepts/PSRule/en-US/about_PSRule_Options.md index f7ca5383f6..dbf45e98a8 100644 --- a/docs/concepts/PSRule/en-US/about_PSRule_Options.md +++ b/docs/concepts/PSRule/en-US/about_PSRule_Options.md @@ -1030,6 +1030,9 @@ variables: ### Execution.SuppressedRuleWarning +This option has been deprecated and will be removed from v3 in favor of `ruleSuppressed`. +Use `ruleSuppressed` instead. + When evaluating rules, it is possible to output suppressed rules as warnings. Suppressed rules will: @@ -1134,6 +1137,120 @@ variables: value: Error ``` +### Execution.RuleExcluded + +Determines how to handle excluded rules. +Regardless of the value, excluded rules are ignored. +By defaut, a rule is excluded silently, however this behaviour can be modified by this option. + +The following preferences are available: + +- `None` (0) - No preference. + Inherits the default of `Ignore`. +- `Ignore` (1) - Continue to execute silently. + This is the default. +- `Warn` (2) - Continue to execute but log a warning. +- `Error` (3) - Abort and throw an error. +- `Debug` (4) - Continue to execute but log a debug message. + +```powershell +# PowerShell: Using the ExecutionRuleExcluded parameter +$option = New-PSRuleOption -ExecutionRuleExcluded 'Warn'; +``` + +```powershell +# PowerShell: Using the Execution.RuleExcluded hashtable key +$option = New-PSRuleOption -Option @{ 'Execution.RuleExcluded' = 'Warn' }; +``` + +```powershell +# PowerShell: Using the ExecutionRuleExcluded parameter to set YAML +Set-PSRuleOption -ExecutionRuleExcluded 'Warn'; +``` + +```yaml +# YAML: Using the execution/ruleExcluded property +execution: + ruleExcluded: Warn +``` + +```bash +# Bash: Using environment variable +export PSRULE_EXECUTION_RULEEXCLUDED=Warn +``` + +```yaml +# GitHub Actions: Using environment variable +env: + PSRULE_EXECUTION_RULEEXCLUDED: Warn +``` + +```yaml +# Azure Pipelines: Using environment variable +variables: +- name: PSRULE_EXECUTION_RULEEXCLUDED + value: Warn +``` + +### Execution.RuleSuppressed + +Determines how to handle suppressed rules. +Regardless of the value, a suppressed rule is ignored. +By defaut, a warning is generated, however this behaviour can be modified by this option. + +This option replaces `suppressedRuleWarning`. +You do not need to configure both options. +If `suppressedRuleWarning` is configured, it will override `ruleSuppressed` with `Warn` or `Ignore` until removal in PSRule v3. + +The following preferences are available: + +- `None` (0) - No preference. + Inherits the default of `Warn`. +- `Ignore` (1) - Continue to execute silently. +- `Warn` (2) - Continue to execute but log a warning. + This is the default. +- `Error` (3) - Abort and throw an error. +- `Debug` (4) - Continue to execute but log a debug message. + +```powershell +# PowerShell: Using the ExecutionRuleSuppressed parameter +$option = New-PSRuleOption -ExecutionRuleSuppressed 'Error'; +``` + +```powershell +# PowerShell: Using the Execution.RuleSuppressed hashtable key +$option = New-PSRuleOption -Option @{ 'Execution.RuleSuppressed' = 'Error' }; +``` + +```powershell +# PowerShell: Using the ExecutionRuleSuppressed parameter to set YAML +Set-PSRuleOption -ExecutionRuleSuppressed 'Error'; +``` + +```yaml +# YAML: Using the execution/ruleSuppressed property +execution: + ruleSuppressed: Error +``` + +```bash +# Bash: Using environment variable +export PSRULE_EXECUTION_RULESUPPRESSED=Error +``` + +```yaml +# GitHub Actions: Using environment variable +env: + PSRULE_EXECUTION_RULESUPPRESSED: Error +``` + +```yaml +# Azure Pipelines: Using environment variable +variables: +- name: PSRULE_EXECUTION_RULESUPPRESSED + value: Error +``` + ### Include.Module Automatically include rules and resources from the specified module. @@ -3210,7 +3327,7 @@ rule: ## NOTE -An online version of this document is available at https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/. +An online version of this document is available at . ## SEE ALSO diff --git a/docs/deprecations.md b/docs/deprecations.md index 44237566ba..9f177686bb 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -7,6 +7,30 @@ discussion: false ## Deprecations for v3 +### Execution options + +PSRule provides a number of execution options that control logging of certain events. +In many cases these options turn a warning on or off. + +These options are deprecated but replaced to provide more choice to when configuring logging options. +Now you can configure the following: + +- `Ignore` (1) - Continue to execute silently. +- `Warn` (2) - Continue to execute but log a warning. + This is the default. +- `Error` (3) - Abort and throw an error. +- `Debug` (4) - Continue to execute but log a debug message. + +The following execution options have been deprecated and will be removed from _v3_. + +- `Execution.SuppressedRuleWarning` is replaced with `Execution.RuleSuppressed`. + Set `Execution.RuleSuppressed` to `Warn` to log a warning from _v2.8.0_. + If both options are set, `Execution.SuppressedRuleWarning` takes precedence until _v3_. + +!!! Tip + You do not need to configure both options. + If you have the deprecated option configured, switch to the new option. + ### Rule output object Several properties of the rule object have been renamed to improve consistency with other objects. diff --git a/docs/upgrade-notes.md b/docs/upgrade-notes.md index 8f7f428eae..f773404f45 100644 --- a/docs/upgrade-notes.md +++ b/docs/upgrade-notes.md @@ -158,7 +158,7 @@ Rules sources in the current working directory are only included if `-Path .` or The old behavior: -```powershell +```powershell title="PowerShell" Set-Location docs\scenarios\azure-resources Get-PSRule @@ -174,7 +174,7 @@ storageAccounts.UseEncryption Use at-rest stora The new behavior: -```powershell +```powershell title="PowerShell" Set-Location docs\scenarios\azure-resources Get-PSRule @@ -217,7 +217,7 @@ Detect uses the following logic: To force usage of the `Client` output style set the `Output.Style` option. For example: -```yaml +```yaml title="ps-rule.yaml" # YAML: Using the output/style property output: style: Client @@ -228,13 +228,13 @@ output: export PSRULE_OUTPUT_STYLE=Client ``` -```yaml +```yaml title="GitHub Actions" # GitHub Actions: Using environment variable env: PSRULE_OUTPUT_STYLE: Client ``` -```yaml +```yaml title="Azure Pipelines" # Azure Pipelines: Using environment variable variables: - name: PSRULE_OUTPUT_STYLE @@ -255,7 +255,7 @@ Previously in PSRule _v0.22.0_ and prior the `$Rule` automatic variable had the For example: -```powershell +```powershell title="PowerShell rules" Rule 'Rule1' { $Rule.TargetName -eq 'Name1'; $Rule.TargetType -eq '.json'; @@ -269,7 +269,7 @@ Rules referencing the deprecated properties of `$Rule` must be updated. For example: -```powershell +```powershell title="PowerShell rules" Rule 'Rule1' { $PSRule.TargetName -eq 'Name1'; $PSRule.TargetType -eq '.json'; diff --git a/schemas/PSRule-options.schema.json b/schemas/PSRule-options.schema.json index ebccded8f7..4c5e69f438 100644 --- a/schemas/PSRule-options.schema.json +++ b/schemas/PSRule-options.schema.json @@ -346,10 +346,11 @@ }, "suppressedRuleWarning": { "type": "boolean", - "title": "Warn on suppressed rules", - "description": "Enable or disable warnings for suppressed rules. The default is true.", - "markdownDescription": "Enable or disable warnings for suppressed rules. The default is `true`. [See help](https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionsuppressedrulewarning)", - "default": true + "title": "Warn on suppressed rules | DEPRECATED", + "description": "This option has been deprecated and will be removed from v3 in favor of ruleSuppressed. Enable or disable warnings for suppressed rules. The default is true.", + "markdownDescription": "This option has been deprecated and will be removed from v3 in favor of `ruleSuppressed`.\n\nEnable or disable warnings for suppressed rules. The default is `true`. [See help](https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionsuppressedrulewarning)", + "default": true, + "deprecated": true }, "suppressionGroupExpired": { "type": "string", @@ -363,6 +364,32 @@ "Debug" ], "default": "Warn" + }, + "ruleExcluded": { + "type": "string", + "title": "Rule excluded", + "description": "Determines how to handle excluded rules. Regardless of the value, excluded rules are ignored. By default, rules are excluded silently. When set to Error, an error is thrown. When set to Warn, a warning is generated. When set to Debug, a message is written to the debug log.", + "markdownDescription": "Determines how to handle excluded rules.\n\nRegardless of the value, excluded rules are ignored. By default, rules are excluded silently.\n\n- When set to `Error`, an error is thrown.\n- When set to `Warn`, a warning is generated.\n- When set to `Debug`, a message is written to the debug log.\n\n[See help](https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionruleexecluded)", + "enum": [ + "Ignore", + "Warn", + "Error", + "Debug" + ], + "default": "Ignore" + }, + "ruleSuppressed": { + "type": "string", + "title": "Rule suppressed", + "description": "Determines how to handle suppressed rules. Regardless of the value, a suppressed rule is ignored. By default, a warning is generated. When set to Error, an error is thrown. When set to Debug, a message is written to the debug log. When set to Ignore, no output will be displayed. This option replaces suppressedRuleWarning. You do not need to configure both options. If suppressedRuleWarning is configured, it will override ruleSuppressed with Warn or Ignore until removal in PSRule v3.", + "markdownDescription": "Determines how to handle suppressed rules.\n\nRegardless of the value, a suppressed rule is ignored. By default, a warning is generated.\n\n- When set to `Error`, an error is thrown.\n- When set to `Debug`, a message is written to the debug log.\n- When set to `Ignore`, no output will be displayed.\n\nThis option replaces `suppressedRuleWarning`. You do not need to configure both options. If `suppressedRuleWarning` is configured, it will override `ruleSuppressed` with `Warn` or `Ignore` until removal in PSRule v3.\n\n[See help](https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionrulesuppressed)", + "enum": [ + "Ignore", + "Warn", + "Error", + "Debug" + ], + "default": "Warn" } }, "additionalProperties": false diff --git a/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs b/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs index 67ec869614..bcf09610be 100644 --- a/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs +++ b/src/PSRule/Common/RunspaceContextDiagnosticExtensions.cs @@ -5,6 +5,7 @@ using System.Threading; using PSRule.Configuration; using PSRule.Definitions; +using PSRule.Definitions.SuppressionGroups; using PSRule.Pipeline; using PSRule.Resources; using PSRule.Runtime; @@ -40,6 +41,17 @@ internal static void WarnRuleNotFound(this RunspaceContext context) context.Writer.WriteWarning(PSRuleResources.RuleNotFound); } + /// + /// The option '{0}' is deprecated and will be removed with PSRule v3. See http://aka.ms/ps-rule/deprecations for more detail. + /// + internal static void WarnDeprecatedOption(this RunspaceContext context, string option) + { + if (context.Writer == null || !context.Writer.ShouldWriteWarning()) + return; + + context.Writer.WriteWarning(PSRuleResources.DeprecatedOption, option); + } + internal static void WarnDuplicateRuleName(this RunspaceContext context, string ruleName) { if (context == null || context.Writer == null || !context.Writer.ShouldWriteWarning()) @@ -66,6 +78,15 @@ internal static void SuppressionGroupExpired(this RunspaceContext context, Resou context.Throw(action, PSRuleResources.SuppressionGroupExpired, suppressionGroupId.Value); } + internal static void RuleExcluded(this RunspaceContext context, ResourceId ruleId) + { + if (context == null || context.Pipeline == null) + return; + + var action = context.Pipeline.Option.Execution.RuleExcluded.GetValueOrDefault(ExecutionOption.Default.RuleExcluded.Value); + context.Throw(action, PSRuleResources.SuppressionGroupExpired, ruleId.Value); + } + internal static void Throw(this RunspaceContext context, ExecutionActionPreference action, string message, params object[] args) { if (context == null || action == ExecutionActionPreference.Ignore) diff --git a/src/PSRule/Configuration/ExecutionOption.cs b/src/PSRule/Configuration/ExecutionOption.cs index e03238f246..3fe828c322 100644 --- a/src/PSRule/Configuration/ExecutionOption.cs +++ b/src/PSRule/Configuration/ExecutionOption.cs @@ -18,12 +18,13 @@ public sealed class ExecutionOption : IEquatable private const LanguageMode DEFAULT_LANGUAGEMODE = Configuration.LanguageMode.FullLanguage; private const bool DEFAULT_INCONCLUSIVEWARNING = true; private const bool DEFAULT_NOTPROCESSEDWARNING = true; - private const bool DEFAULT_SUPPRESSEDRULEWARNING = true; private const bool DEFAULT_ALIASREFERENCEWARNING = true; private const bool DEFAULT_INVARIANTCULTUREWARNING = true; private const ExecutionActionPreference DEFAULT_DUPLICATERESOURCEID = ExecutionActionPreference.Error; private const SessionState DEFAULT_INITIALSESSIONSTATE = SessionState.BuiltIn; private const ExecutionActionPreference DEFAULT_SUPPRESSIONGROUPEXPIRED = ExecutionActionPreference.Warn; + private const ExecutionActionPreference DEFAULT_RULEEXCLUDED = ExecutionActionPreference.Ignore; + private const ExecutionActionPreference DEFAULT_RULESUPPRESSED = ExecutionActionPreference.Warn; internal static readonly ExecutionOption Default = new() { @@ -34,8 +35,9 @@ public sealed class ExecutionOption : IEquatable InvariantCultureWarning = DEFAULT_INVARIANTCULTUREWARNING, InitialSessionState = DEFAULT_INITIALSESSIONSTATE, NotProcessedWarning = DEFAULT_NOTPROCESSEDWARNING, - SuppressedRuleWarning = DEFAULT_SUPPRESSEDRULEWARNING, SuppressionGroupExpired = DEFAULT_SUPPRESSIONGROUPEXPIRED, + RuleExcluded = DEFAULT_RULEEXCLUDED, + RuleSuppressed = DEFAULT_RULESUPPRESSED, }; /// @@ -50,8 +52,12 @@ public ExecutionOption() InvariantCultureWarning = null; InitialSessionState = null; NotProcessedWarning = null; +#pragma warning disable CS0612 // Type or member is obsolete SuppressedRuleWarning = null; +#pragma warning restore CS0612 // Type or member is obsolete SuppressionGroupExpired = null; + RuleExcluded = null; + RuleSuppressed = null; } /// @@ -70,8 +76,12 @@ public ExecutionOption(ExecutionOption option) InvariantCultureWarning = option.InvariantCultureWarning; InitialSessionState = option.InitialSessionState; NotProcessedWarning = option.NotProcessedWarning; +#pragma warning disable CS0612 // Type or member is obsolete SuppressedRuleWarning = option.SuppressedRuleWarning; +#pragma warning restore CS0612 // Type or member is obsolete SuppressionGroupExpired = option.SuppressionGroupExpired; + RuleExcluded = option.RuleExcluded; + RuleSuppressed = option.RuleSuppressed; } /// @@ -83,6 +93,7 @@ public override bool Equals(object obj) /// public bool Equals(ExecutionOption other) { +#pragma warning disable CS0612 // Type or member is obsolete return other != null && AliasReferenceWarning == other.AliasReferenceWarning && DuplicateResourceId == other.DuplicateResourceId && @@ -91,8 +102,11 @@ public bool Equals(ExecutionOption other) InvariantCultureWarning == other.InvariantCultureWarning && InitialSessionState == other.InitialSessionState && NotProcessedWarning == other.NotProcessedWarning && - SuppressedRuleWarning == other.NotProcessedWarning && - SuppressionGroupExpired == other.SuppressionGroupExpired; + SuppressedRuleWarning == other.SuppressedRuleWarning && + SuppressionGroupExpired == other.SuppressionGroupExpired && + RuleExcluded == other.RuleExcluded && + RuleSuppressed == other.RuleSuppressed; +#pragma warning restore CS0612 // Type or member is obsolete } /// @@ -108,8 +122,12 @@ public override int GetHashCode() hash = hash * 23 + (InvariantCultureWarning.HasValue ? InvariantCultureWarning.Value.GetHashCode() : 0); hash = hash * 23 + (InitialSessionState.HasValue ? InitialSessionState.Value.GetHashCode() : 0); hash = hash * 23 + (NotProcessedWarning.HasValue ? NotProcessedWarning.Value.GetHashCode() : 0); +#pragma warning disable CS0612 // Type or member is obsolete hash = hash * 23 + (SuppressedRuleWarning.HasValue ? SuppressedRuleWarning.Value.GetHashCode() : 0); +#pragma warning restore CS0612 // Type or member is obsolete hash = hash * 23 + (SuppressionGroupExpired.HasValue ? SuppressionGroupExpired.Value.GetHashCode() : 0); + hash = hash * 23 + (RuleExcluded.HasValue ? RuleExcluded.Value.GetHashCode() : 0); + hash = hash * 23 + (RuleSuppressed.HasValue ? RuleSuppressed.Value.GetHashCode() : 0); return hash; } } @@ -120,6 +138,7 @@ public override int GetHashCode() /// internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) { +#pragma warning disable CS0612 // Type or member is obsolete var result = new ExecutionOption(o1) { AliasReferenceWarning = o1.AliasReferenceWarning ?? o2.AliasReferenceWarning, @@ -130,7 +149,11 @@ internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) SuppressedRuleWarning = o1.SuppressedRuleWarning ?? o2.SuppressedRuleWarning, InvariantCultureWarning = o1.InvariantCultureWarning ?? o2.InvariantCultureWarning, InitialSessionState = o1.InitialSessionState ?? o2.InitialSessionState, + SuppressionGroupExpired = o1.SuppressionGroupExpired ?? o2.SuppressionGroupExpired, + RuleExcluded = o1.RuleExcluded ?? o2.RuleExcluded, + RuleSuppressed = o1.RuleSuppressed ?? o2.RuleSuppressed, }; +#pragma warning restore CS0612 // Type or member is obsolete return result; } @@ -196,9 +219,34 @@ internal static ExecutionOption Combine(ExecutionOption o1, ExecutionOption o2) /// /// Determines if a warning is raised when a rule is suppressed. /// - [DefaultValue(null)] + [DefaultValue(null), Obsolete("Use RuleSuppressed instead. See http://aka.ms/ps-rule/deprecations for more detail.")] public bool? SuppressedRuleWarning { get; set; } + /// + /// Determines how to handle rules that are excluded. + /// By default, a excluded rules do not generated any output. + /// When set to Error, an error is thrown. + /// When set to Warn, a warning is generated. + /// When set to Debug, a message is written to the debug log. + /// + [DefaultValue(null)] + public ExecutionActionPreference? RuleExcluded { get; set; } + + /// + /// Determines how to handle rules that are suppressed. + /// This option replaces . + /// By default, a warning is generated. + /// When set to Error, an error is thrown. + /// When set to Debug, a message is written to the debug log. + /// When set to Ignore, no output will be displayed. + /// + /// + /// If is true this option will be overridden to Warn. + /// If is false this option will be overridden to Ignore. + /// + [DefaultValue(null)] + public ExecutionActionPreference? RuleSuppressed { get; set; } + internal void Load(EnvironmentHelper env) { if (env.TryBool("PSRULE_EXECUTION_ALIASREFERENCEWARNING", out var bvalue)) @@ -223,10 +271,18 @@ internal void Load(EnvironmentHelper env) NotProcessedWarning = bvalue; if (env.TryBool("PSRULE_EXECUTION_SUPPRESSEDRULEWARNING", out bvalue)) +#pragma warning disable CS0612 // Type or member is obsolete SuppressedRuleWarning = bvalue; +#pragma warning restore CS0612 // Type or member is obsolete if (env.TryEnum("PSRULE_EXECUTION_SUPPRESSIONGROUPEXPIRED", out ExecutionActionPreference suppressionGroupExpired)) SuppressionGroupExpired = suppressionGroupExpired; + + if (env.TryEnum("PSRULE_EXECUTION_RULEEXCLUDED", out ExecutionActionPreference ruleExcluded)) + RuleExcluded = ruleExcluded; + + if (env.TryEnum("PSRULE_EXECUTION_RULESUPPRESSED", out ExecutionActionPreference ruleSuppressed)) + RuleSuppressed = ruleSuppressed; } internal void Load(Dictionary index) @@ -253,10 +309,18 @@ internal void Load(Dictionary index) NotProcessedWarning = bvalue; if (index.TryPopBool("Execution.SuppressedRuleWarning", out bvalue)) +#pragma warning disable CS0612 // Type or member is obsolete SuppressedRuleWarning = bvalue; +#pragma warning restore CS0612 // Type or member is obsolete if (index.TryPopEnum("Execution.SuppressionGroupExpired", out ExecutionActionPreference suppressionGroupExpired)) SuppressionGroupExpired = suppressionGroupExpired; + + if (index.TryPopEnum("Execution.RuleExcluded", out ExecutionActionPreference ruleExcluded)) + RuleExcluded = ruleExcluded; + + if (index.TryPopEnum("Execution.RuleSuppressed", out ExecutionActionPreference ruleSuppressed)) + RuleSuppressed = ruleSuppressed; } } } diff --git a/src/PSRule/Definitions/DependencyGraphBuilder.cs b/src/PSRule/Definitions/DependencyGraphBuilder.cs index 9fc03aa3bd..9cff623e2d 100644 --- a/src/PSRule/Definitions/DependencyGraphBuilder.cs +++ b/src/PSRule/Definitions/DependencyGraphBuilder.cs @@ -7,6 +7,7 @@ using System.Threading; using PSRule.Pipeline; using PSRule.Resources; +using PSRule.Rules; using PSRule.Runtime; namespace PSRule.Definitions @@ -40,6 +41,8 @@ public void Include(DependencyTargetCollection index, Func filter) if (filter == null || filter(item)) Include(index, item, parentId: null); + else if (item is RuleBlock) + _Context.RuleExcluded(item.Id); } } diff --git a/src/PSRule/PSRule.psm1 b/src/PSRule/PSRule.psm1 index e16db570bd..0ec51d5499 100644 --- a/src/PSRule/PSRule.psm1 +++ b/src/PSRule/PSRule.psm1 @@ -106,7 +106,7 @@ function Invoke-PSRule { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -264,7 +264,7 @@ function Test-PSRuleTarget { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -383,7 +383,7 @@ function Get-PSRuleTarget { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; $isDeviceGuard = IsDeviceGuardEnabled; @@ -537,7 +537,7 @@ function Assert-PSRule { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -688,7 +688,7 @@ function Get-PSRule { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -808,7 +808,7 @@ function Get-PSRuleBaseline { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -916,7 +916,7 @@ function Export-PSRuleBaseline { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -1022,7 +1022,7 @@ function Get-PSRuleHelp { } # Get an options object - $Option = New-PSRuleOption @optionParams; + $Option = New-PSRuleOption @optionParams -WarningAction SilentlyContinue; # Discover scripts in the specified paths $sourceParams = @{ }; @@ -1197,6 +1197,7 @@ function New-PSRuleOption { # Sets the Execution.SuppressedRuleWarning option [Parameter(Mandatory = $False)] [Alias('ExecutionSuppressedRuleWarning')] + [System.Obsolete('Use ExecutionRuleSuppressed instead. See http://aka.ms/ps-rule/deprecations for more detail.')] [System.Boolean]$SuppressedRuleWarning = $True, # Sets the Execution.SuppressionGroupExpired option @@ -1204,6 +1205,14 @@ function New-PSRuleOption { [Alias('ExecutionSuppressionGroupExpired')] [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Execution.RuleExcluded option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + + # Sets the Execution.RuleSuppressed option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Include.Module option [Parameter(Mandatory = $False)] [String[]]$IncludeModule, @@ -1498,6 +1507,7 @@ function Set-PSRuleOption { # Sets the Execution.SuppressedRuleWarning option [Parameter(Mandatory = $False)] [Alias('ExecutionSuppressedRuleWarning')] + [System.Obsolete('Use ExecutionRuleSuppressed instead. See http://aka.ms/ps-rule/deprecations for more detail.')] [System.Boolean]$SuppressedRuleWarning = $True, # Sets the Execution.SuppressionGroupExpired option @@ -1505,6 +1515,14 @@ function Set-PSRuleOption { [Alias('ExecutionSuppressionGroupExpired')] [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Execution.RuleExcluded option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + + # Sets the Execution.RuleSuppressed option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Include.Module option [Parameter(Mandatory = $False)] [String[]]$IncludeModule, @@ -2253,6 +2271,14 @@ function SetOptions { [Alias('ExecutionSuppressionGroupExpired')] [PSRule.Configuration.ExecutionActionPreference]$SuppressionGroupExpired = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Execution.RuleExcluded option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleExcluded = [PSRule.Configuration.ExecutionActionPreference]::Ignore, + + # Sets the Execution.RuleSuppressed option + [Parameter(Mandatory = $False)] + [PSRule.Configuration.ExecutionActionPreference]$ExecutionRuleSuppressed = [PSRule.Configuration.ExecutionActionPreference]::Warn, + # Sets the Include.Module option [Parameter(Mandatory = $False)] [String[]]$IncludeModule, @@ -2465,6 +2491,16 @@ function SetOptions { $Option.Execution.SuppressionGroupExpired = $SuppressionGroupExpired; } + # Sets option Execution.RuleExcluded + if ($PSBoundParameters.ContainsKey('ExecutionRuleExcluded')) { + $Option.Execution.RuleExcluded = $ExecutionRuleExcluded; + } + + # Sets option Execution.RuleSuppressed + if ($PSBoundParameters.ContainsKey('ExecutionRuleSuppressed')) { + $Option.Execution.RuleSuppressed = $ExecutionRuleSuppressed; + } + # Sets option Include.Module if ($PSBoundParameters.ContainsKey('IncludeModule')) { $Option.Include.Module = $IncludeModule; diff --git a/src/PSRule/Pipeline/InvokeRulePipeline.cs b/src/PSRule/Pipeline/InvokeRulePipeline.cs index 536326cbc1..e64f39c70d 100644 --- a/src/PSRule/Pipeline/InvokeRulePipeline.cs +++ b/src/PSRule/Pipeline/InvokeRulePipeline.cs @@ -36,6 +36,11 @@ internal InvokeRulePipeline(PipelineContext context, Source[] source, IPipelineW if (RuleCount == 0) Context.WarnRuleNotFound(); +#pragma warning disable CS0612 // Type or member is obsolete + if (context.Option.Execution.SuppressedRuleWarning.HasValue) + Context.WarnDeprecatedOption("Execution.SuppressedRuleWarning"); +#pragma warning restore CS0612 // Type or member is obsolete + _Outcome = outcome; _IsSummary = context.Option.Output.As.Value == ResultFormat.Summary; _Summary = _IsSummary ? new Dictionary() : null; @@ -119,14 +124,14 @@ private InvokeResult ProcessTargetObject(TargetObject targetObject) suppressedRuleCounter++; if (!_IsSummary) - Context.WarnRuleSuppressed(ruleId: ruleRecord.RuleId); + Context.RuleSuppressed(ruleId: ruleRecord.RuleId); } // Check for suppression group else if (_SuppressionGroupFilter.TrySuppressionGroup(ruleId: ruleRecord.RuleId, targetObject, out var suppression)) { ruleRecord.OutcomeReason = RuleOutcomeReason.Suppressed; if (!_IsSummary) - Context.WarnRuleSuppressionGroup(ruleId: ruleRecord.RuleId, suppression); + Context.RuleSuppressionGroup(ruleId: ruleRecord.RuleId, suppression); else suppressionGroupCounter[suppression] = suppressionGroupCounter.TryGetValue(suppression, out var count) ? ++count : 1; } @@ -171,7 +176,7 @@ private InvokeResult ProcessTargetObject(TargetObject targetObject) Context.WarnRuleCountSuppressed(ruleCount: suppressedRuleCounter); foreach (var keyValuePair in suppressionGroupCounter) - Context.WarnRuleSuppressionGroupCount(suppression: keyValuePair.Key, count: keyValuePair.Value); + Context.RuleSuppressionGroupCount(suppression: keyValuePair.Key, count: keyValuePair.Value); } return result; } diff --git a/src/PSRule/Resources/PSRuleResources.Designer.cs b/src/PSRule/Resources/PSRuleResources.Designer.cs index d206435e4f..c63ed757c2 100644 --- a/src/PSRule/Resources/PSRuleResources.Designer.cs +++ b/src/PSRule/Resources/PSRuleResources.Designer.cs @@ -204,6 +204,15 @@ internal static string DependencyNotFound { } } + /// + /// Looks up a localized string similar to The option '{0}' is deprecated and will be removed with PSRule v3. See http://aka.ms/ps-rule/deprecations for more detail.. + /// + internal static string DeprecatedOption { + get { + return ResourceManager.GetString("DeprecatedOption", resourceCulture); + } + } + /// /// Looks up a localized string similar to The resource '{0}' is using a duplicate resource identifier. A resource with the identifier '{1}' already exists. Each resource must have a unique name, ref, and aliases. See https://aka.ms/ps-rule/naming for guidance on naming within PSRule.. /// diff --git a/src/PSRule/Resources/PSRuleResources.resx b/src/PSRule/Resources/PSRuleResources.resx index 66e53dbee0..bf12dd7b6a 100644 --- a/src/PSRule/Resources/PSRuleResources.resx +++ b/src/PSRule/Resources/PSRuleResources.resx @@ -400,4 +400,7 @@ PSR0001: Unable to read options file '{0}'. Please check the file is valid, indented correctly, and encoded as UTF-8. See https://aka.ms/ps-rule/ts-options. {1} + + The option '{0}' is deprecated and will be removed with PSRule v3. See http://aka.ms/ps-rule/deprecations for more detail. + \ No newline at end of file diff --git a/src/PSRule/Runtime/RunspaceContext.cs b/src/PSRule/Runtime/RunspaceContext.cs index 7ed138e5a6..29c1bb411b 100644 --- a/src/PSRule/Runtime/RunspaceContext.cs +++ b/src/PSRule/Runtime/RunspaceContext.cs @@ -74,7 +74,7 @@ internal sealed class RunspaceContext : IDisposable private readonly bool _InconclusiveWarning; private readonly bool _NotProcessedWarning; - private readonly bool _SuppressedRuleWarning; + private readonly ExecutionActionPreference _SuppressedRuleWarning; private readonly bool _InvariantCultureWarning; private readonly OutcomeLogStream _FailStream; private readonly OutcomeLogStream _PassStream; @@ -108,7 +108,14 @@ internal RunspaceContext(PipelineContext pipeline, IPipelineWriter writer) _InconclusiveWarning = Pipeline.Option.Execution.InconclusiveWarning ?? ExecutionOption.Default.InconclusiveWarning.Value; _NotProcessedWarning = Pipeline.Option.Execution.NotProcessedWarning ?? ExecutionOption.Default.NotProcessedWarning.Value; - _SuppressedRuleWarning = Pipeline.Option.Execution.SuppressedRuleWarning ?? ExecutionOption.Default.SuppressedRuleWarning.Value; + +#pragma warning disable CS0612 // Type or member is obsolete + if (Pipeline.Option.Execution.SuppressedRuleWarning.HasValue) + _SuppressedRuleWarning = Pipeline.Option.Execution.SuppressedRuleWarning.Value ? ExecutionActionPreference.Warn : ExecutionActionPreference.Ignore; + else + _SuppressedRuleWarning = Pipeline.Option.Execution.RuleSuppressed.GetValueOrDefault(ExecutionOption.Default.RuleSuppressed.Value); +#pragma warning restore CS0612 // Type or member is obsolete + _InvariantCultureWarning = Pipeline.Option.Execution.InvariantCultureWarning ?? ExecutionOption.Default.InvariantCultureWarning.Value; _FailStream = Pipeline.Option.Logging.RuleFail ?? LoggingOption.Default.RuleFail.Value; _PassStream = Pipeline.Option.Logging.RulePass ?? LoggingOption.Default.RulePass.Value; @@ -240,44 +247,36 @@ public void WarnObjectNotProcessed() Writer.WriteWarning(PSRuleResources.ObjectNotProcessed, Binding.TargetName); } - public void WarnRuleSuppressed(string ruleId) + public void RuleSuppressed(string ruleId) { - if (Writer == null || !Writer.ShouldWriteWarning() || !_SuppressedRuleWarning) - { - return; - } - - Writer.WriteWarning(PSRuleResources.RuleSuppressed, ruleId, Binding.TargetName); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleSuppressed, ruleId, Binding.TargetName); } public void WarnRuleCountSuppressed(int ruleCount) { - if (Writer == null || !Writer.ShouldWriteWarning() || !_SuppressedRuleWarning) - return; - - Writer.WriteWarning(PSRuleResources.RuleCountSuppressed, ruleCount, Binding.TargetName); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleCountSuppressed, ruleCount, Binding.TargetName); } - public void WarnRuleSuppressionGroup(string ruleId, ISuppressionInfo suppression) + public void RuleSuppressionGroup(string ruleId, ISuppressionInfo suppression) { - if (Writer == null || suppression == null || !Writer.ShouldWriteWarning() || !_SuppressedRuleWarning) + if (suppression == null) return; if (suppression.Synopsis != null && suppression.Synopsis.HasValue) - Writer.WriteWarning(PSRuleResources.RuleSuppressionGroupExtended, ruleId, suppression.Id, Binding.TargetName, suppression.Synopsis.Text); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleSuppressionGroupExtended, ruleId, suppression.Id, Binding.TargetName, suppression.Synopsis.Text); else - Writer.WriteWarning(PSRuleResources.RuleSuppressionGroup, ruleId, suppression.Id, Binding.TargetName); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleSuppressionGroup, ruleId, suppression.Id, Binding.TargetName); } - public void WarnRuleSuppressionGroupCount(ISuppressionInfo suppression, int count) + public void RuleSuppressionGroupCount(ISuppressionInfo suppression, int count) { - if (Writer == null || suppression == null || !Writer.ShouldWriteWarning() || !_SuppressedRuleWarning) + if (suppression == null) return; if (suppression.Synopsis != null && suppression.Synopsis.HasValue) - Writer.WriteWarning(PSRuleResources.RuleSuppressionGroupExtendedCount, count, suppression.Id, Binding.TargetName, suppression.Synopsis.Text); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleSuppressionGroupExtendedCount, count, suppression.Id, Binding.TargetName, suppression.Synopsis.Text); else - Writer.WriteWarning(PSRuleResources.RuleSuppressionGroupCount, count, suppression.Id, Binding.TargetName); + this.Throw(_SuppressedRuleWarning, PSRuleResources.RuleSuppressionGroupCount, count, suppression.Id, Binding.TargetName); } public void ErrorInvaildRuleResult() @@ -566,9 +565,7 @@ private static int GetPositionMessageOffset(string positionMessage) private string GetLogPrefix() { - if (_LogPrefix == null) - _LogPrefix = $"[PSRule][R][{_ObjectNumber}][{RuleRecord?.RuleId}]"; - + _LogPrefix ??= $"[PSRule][R][{_ObjectNumber}][{RuleRecord?.RuleId}]"; return _LogPrefix ?? string.Empty; } @@ -660,8 +657,7 @@ public RuleRecord EnterRuleBlock(RuleBlock ruleBlock) extent: ruleBlock.Extent ); - if (Writer != null) - Writer.EnterScope(ruleBlock.Name); + Writer?.EnterScope(ruleBlock.Name); // Starts rule execution timer _RuleTimer.Restart(); @@ -681,8 +677,7 @@ public void ExitRuleBlock() for (var i = 0; i < _Reason.Count; i++) RuleRecord._Detail.Add(_Reason[i]); - if (Writer != null) - Writer.ExitScope(); + Writer?.ExitScope(); _LogPrefix = null; RuleRecord = null; diff --git a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 index a5b4eca0e5..2adf459ae4 100644 --- a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 @@ -1212,7 +1212,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { Context 'Detail' { It 'Show Warnings' { - $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -SuppressedRuleWarning $True -OutputAs Detail -InvariantCultureWarning $False; + $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -ExecutionRuleSuppressed Warn -OutputAs Detail -InvariantCultureWarning $False; $Null = $testObject | Invoke-PSRule -Path $ruleFilePath -Option $option -Name 'FromFile1', 'FromFile2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1226,7 +1226,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'No warnings' { - $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -SuppressedRuleWarning $False -OutputAs Detail -InvariantCultureWarning $False; + $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -ExecutionRuleSuppressed Ignore -OutputAs Detail -InvariantCultureWarning $False; $Null = $testObject | Invoke-PSRule -Path $ruleFilePath -Option $option -Name 'FromFile1', 'FromFile2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1237,7 +1237,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { Context 'Summary' { It 'Show warnings' { - $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -SuppressedRuleWarning $True -OutputAs Summary -InvariantCultureWarning $False; + $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -ExecutionRuleSuppressed Warn -OutputAs Summary -InvariantCultureWarning $False; $Null = $testObject | Invoke-PSRule -Path $ruleFilePath -Option $option -Name 'FromFile1', 'FromFile2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1249,7 +1249,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'No warnings' { - $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -SuppressedRuleWarning $False -OutputAs Summary -InvariantCultureWarning $False; + $option = New-PSRuleOption -SuppressTargetName @{ FromFile1 = 'TestObject1'; FromFile2 = 'TestObject1'; } -ExecutionRuleSuppressed Ignore -OutputAs Summary -InvariantCultureWarning $False; $Null = $testObject | Invoke-PSRule -Path $ruleFilePath -Option $option -Name 'FromFile1', 'FromFile2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1293,7 +1293,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { Context 'Detail' { It 'Show warnings' { - $option = New-PSRuleOption -SuppressedRuleWarning $True -OutputAs Detail -InvariantCultureWarning $False -OutputCulture 'en-US'; + $option = New-PSRuleOption -ExecutionRuleSuppressed Warn -OutputAs Detail -InvariantCultureWarning $False -OutputCulture 'en-US'; $Null = $testObject | Invoke-PSRule @invokeParams -Option $option -Name 'FromFile1', 'FromFile2', 'WithTag2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1317,7 +1317,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'Show warnings for all rules when rule property is null or empty' { - $option = New-PSRuleOption -SuppressedRuleWarning $True -OutputAs Detail -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; + $option = New-PSRuleOption -ExecutionRuleSuppressed Warn -OutputAs Detail -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; $Null = $testObject | Invoke-PSRule @invokeParams2 -Option $option -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1329,7 +1329,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'No warnings' { - $option = New-PSRuleOption -SuppressedRuleWarning $False -OutputAs Detail -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; + $option = New-PSRuleOption -ExecutionRuleSuppressed Ignore -OutputAs Detail -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; $Null = $testObject | Invoke-PSRule @invokeParams -Option $option -Name 'FromFile1', 'FromFile2', 'WithTag2' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1340,7 +1340,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { Context 'Summary' { It 'Show warnings' { - $option = New-PSRuleOption -SuppressedRuleWarning $True -OutputAs Summary -InvariantCultureWarning $False -SuppressionGroupExpired Ignore -OutputCulture 'en-US'; + $option = New-PSRuleOption -ExecutionRuleSuppressed Warn -OutputAs Summary -InvariantCultureWarning $False -SuppressionGroupExpired Ignore -OutputCulture 'en-US'; $Null = $testObject | Invoke-PSRule @invokeParams -Option $option -Name 'FromFile3', 'FromFile5', 'WithTag3' -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1358,7 +1358,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'Show warnings for all rules when rule property is null or empty' { - $option = New-PSRuleOption -SuppressedRuleWarning $True -OutputAs Summary -InvariantCultureWarning $False; + $option = New-PSRuleOption -ExecutionRuleSuppressed Warn -OutputAs Summary -InvariantCultureWarning $False; $Null = $testObject | Invoke-PSRule @invokeParams2 -Option $option -WarningVariable outWarnings -WarningAction SilentlyContinue; @@ -1372,7 +1372,7 @@ Describe 'Invoke-PSRule' -Tag 'Invoke-PSRule','Common' { } It 'No warnings' { - $option = New-PSRuleOption -SuppressedRuleWarning $False -OutputAs Summary -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; + $option = New-PSRuleOption -ExecutionRuleSuppressed Ignore -OutputAs Summary -InvariantCultureWarning $False -SuppressionGroupExpired Ignore; $Null = $testObject | Invoke-PSRule @invokeParams -Option $option -Name 'FromFile3', 'FromFile5', 'WithTag3' -WarningVariable outWarnings -WarningAction SilentlyContinue; diff --git a/tests/PSRule.Tests/PSRule.Options.Tests.ps1 b/tests/PSRule.Tests/PSRule.Options.Tests.ps1 index 8e66223353..ef4f37387b 100644 --- a/tests/PSRule.Tests/PSRule.Options.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Options.Tests.ps1 @@ -703,7 +703,7 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' { Context 'Read Execution.SuppressedRuleWarning' { It 'from default' { $option = New-PSRuleOption -Default; - $option.Execution.SuppressedRuleWarning | Should -Be $True; + $option.Execution.SuppressedRuleWarning | Should -Be $Null; } It 'from Hashtable' { @@ -779,10 +779,99 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' { Remove-Item 'Env:PSRULE_EXECUTION_SUPPRESSIONGROUPEXPIRED' -Force; } } + } + + Context 'Read Execution.RuleExcluded' { + It 'from default' { + $option = New-PSRuleOption -Default; + $option.Execution.RuleExcluded | Should -Be 'Ignore' + } + + It 'from Hashtable' { + $option = New-PSRuleOption -Option @{ 'Execution.RuleExcluded' = 'error' }; + $option.Execution.RuleExcluded | Should -Be 'Error'; + + $option = New-PSRuleOption -Option @{ 'Execution.RuleExcluded' = 'Error' }; + $option.Execution.RuleExcluded | Should -Be 'Error'; + } + + It 'from YAML' { + $option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml'); + $option.Execution.RuleExcluded | Should -Be 'Warn'; + } + + It 'from Environment' { + try { + # With enum + $Env:PSRULE_EXECUTION_RULEEXCLUDED = 'error'; + $option = New-PSRuleOption; + $option.Execution.RuleExcluded | Should -Be 'Error'; + + # With enum + $Env:PSRULE_EXECUTION_RULEEXCLUDED = 'Error'; + $option = New-PSRuleOption; + $option.Execution.RuleExcluded | Should -Be 'Error'; + + # With int + $Env:PSRULE_EXECUTION_RULEEXCLUDED = '3'; + $option = New-PSRuleOption; + $option.Execution.RuleExcluded | Should -Be 'Error'; + } + finally { + Remove-Item 'Env:PSRULE_EXECUTION_RULEEXCLUDED' -Force; + } + } It 'from parameter' { - $option = New-PSRuleOption -SuppressionGroupExpired 'Error' -Path $emptyOptionsFilePath; - $option.Execution.SuppressionGroupExpired | Should -Be 'Error'; + $option = New-PSRuleOption -ExecutionRuleExcluded 'Error' -Path $emptyOptionsFilePath; + $option.Execution.RuleExcluded | Should -Be 'Error'; + } + } + + Context 'Read Execution.RuleSuppressed' { + It 'from default' { + $option = New-PSRuleOption -Default; + $option.Execution.RuleSuppressed | Should -Be 'Warn' + } + + It 'from Hashtable' { + $option = New-PSRuleOption -Option @{ 'Execution.RuleSuppressed' = 'error' }; + $option.Execution.RuleSuppressed | Should -Be 'Error'; + + $option = New-PSRuleOption -Option @{ 'Execution.RuleSuppressed' = 'Error' }; + $option.Execution.RuleSuppressed | Should -Be 'Error'; + } + + It 'from YAML' { + $option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml'); + $option.Execution.RuleSuppressed | Should -Be 'Error'; + } + + It 'from Environment' { + try { + # With enum + $Env:PSRULE_EXECUTION_RULESUPPRESSED = 'error'; + $option = New-PSRuleOption; + $option.Execution.RuleSuppressed | Should -Be 'Error'; + + # With enum + $Env:PSRULE_EXECUTION_RULESUPPRESSED = 'Error'; + $option = New-PSRuleOption; + $option.Execution.RuleSuppressed | Should -Be 'Error'; + + # With int + $Env:PSRULE_EXECUTION_RULESUPPRESSED = '3'; + $option = New-PSRuleOption; + $option.Execution.RuleSuppressed | Should -Be 'Error'; + } + finally { + Remove-Item 'Env:PSRULE_EXECUTION_RULESUPPRESSED' -Force; + } + } + + It 'from parameter' { + $option = New-PSRuleOption -ExecutionRuleSuppressed 'Error' -Path $emptyOptionsFilePath; + $option.Execution.RuleSuppressed | Should -Be 'Error'; } } diff --git a/tests/PSRule.Tests/PSRule.Tests.yml b/tests/PSRule.Tests/PSRule.Tests.yml index 72bc70c663..c71f8706b4 100644 --- a/tests/PSRule.Tests/PSRule.Tests.yml +++ b/tests/PSRule.Tests/PSRule.Tests.yml @@ -58,6 +58,8 @@ execution: notProcessedWarning: false suppressedRuleWarning: false suppressionGroupExpired: Debug + ruleExcluded: Warn + ruleSuppressed: Error # Configure input options input: