зеркало из https://github.com/microsoft/PSRule.git
- Fix handling of non-boolean results in rules. #187
This commit is contained in:
Родитель
536442ea8a
Коммит
e3b3695c80
|
@ -1,6 +1,7 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
- Fix handling of non-boolean results in rules. Rule is failed with more specific error message. [#187](https://github.com/BernieWhite/PSRule/issues/187)
|
||||
- Include .ps1 files that are specified directly with `-Path`, instead of only .rule.ps1 files. [#182](https://github.com/BernieWhite/PSRule/issues/182)
|
||||
- Improved warning message displayed when no Rule.ps1 files are founds.
|
||||
|
||||
|
|
|
@ -4,30 +4,31 @@
|
|||
|
||||
## SHORT DESCRIPTION
|
||||
|
||||
Describes the language keywords that can be used within PSRule document definitions.
|
||||
Describes the language keywords that can be used within PSRule rule definitions.
|
||||
|
||||
## LONG DESCRIPTION
|
||||
|
||||
PSRule lets you define rules using PowerShell blocks. To create a rule use the `Rule` keyword. Within a rule several assertions can be used.
|
||||
PSRule lets you define rules using PowerShell blocks. To define a rule use the `Rule` keyword.
|
||||
|
||||
- Assertion - A specific test that always evaluates to true or false.
|
||||
- [Rule](#rule) - Creates a rule definition.
|
||||
|
||||
The following are the built-in keywords that can be used within PSRule:
|
||||
The following are the built-in keywords that can be used within a rule definition:
|
||||
|
||||
- [Rule](#rule) - A rule definition
|
||||
- [Exists](#exists) - Assert that a field or property must exist
|
||||
- [Match](#match) - Assert that the field must match any of the regular expressions
|
||||
- [AnyOf](#anyof) - Assert that any of the child expressions must be true
|
||||
- [AllOf](#allof) - Assert that all of the child expressions must be true
|
||||
- [Within](#within) - Assert that the field must match any of the values
|
||||
- [TypeOf](#typeof) - Assert that the object must be of a specific type
|
||||
- [Exists](#exists) - Assert that a field or property must exist.
|
||||
- [Match](#match) - Assert that the field must match any of the regular expressions.
|
||||
- [AnyOf](#anyof) - Assert that any of the child expressions must be true.
|
||||
- [AllOf](#allof) - Assert that all of the child expressions must be true.
|
||||
- [Within](#within) - Assert that the field must match any of the values.
|
||||
- [TypeOf](#typeof) - Assert that the object must be of a specific type.
|
||||
- [Recommend](#recommend) - Return the process to resolve the issue and pass the rule.
|
||||
|
||||
### Rule
|
||||
|
||||
A `Rule` definition describes an individual business rule that will be applied to pipeline objects.
|
||||
A `Rule` definition describes an individual business rule that will be executed against each input object. Input objects can be passed on the PowerShell pipeline or supplied from file.
|
||||
|
||||
To define a Rule use the `Rule` keyword followed by a name and a pair of squiggly brackets `{`. Within the `{ }` one or more expressions can be used.
|
||||
To define a Rule use the `Rule` keyword followed by a name and a pair of squiggly brackets `{`. Within the `{ }` one or more conditions can be used.
|
||||
|
||||
Conditions determine if the input object either _Pass_ or _Fail_ the rule.
|
||||
|
||||
Syntax:
|
||||
|
||||
|
@ -43,7 +44,18 @@ Rule [-Name] <string> [-Tag <hashtable>] [-Type <string[]>] [-If <scriptBlock>]
|
|||
- `If` - A script precondition that must evaluate to `$True` before the rule is executed.
|
||||
- `DependsOn` - A list of rules this rule depends on. Rule dependencies must execute successfully before this rule is executed.
|
||||
- `Configure` - A set of default configuration values. These values are only used when the baseline configuration does not contain the key.
|
||||
- `Body` - A script block definition of the rule containing one or more PSRule keywords and PowerShell expressions.
|
||||
- `Body` - A script block that specifies one or more conditions that are required for the rule to _Pass_.
|
||||
|
||||
A condition is any valid PowerShell that return either `$True` or `$False`. Optionally, PSRule keywords can be used to help build out conditions quickly. When a rule contains more then one condition, all must return `$True` for the rule to _Pass_. If any one condition returns `$False` the rule has failed.
|
||||
|
||||
The following restrictions apply:
|
||||
|
||||
- Rule conditions should only return `$True` or `$False`. Other objects should be caught with `Out-Null` or null assigned like `$Null = `.
|
||||
- The `Rule` keyword can not be nested in a `Rule` definition.
|
||||
- Variables and functions defined within `.Rule.ps1` files, but outside the `Rule` definition block are not accessible unless the `Global` scope is applied.
|
||||
- Functions and variables within the caller's scope (the scope calling `Invoke-PSRule`, `Get-PSRule`, `Test-PSRuleTarget`) are not accessible.
|
||||
- Cmdlets that require user interaction are not supported, i.e. `Read-Host`.
|
||||
- `Write-Debug` is not currently supported, `Write-Error`, `Write-Warning`, `Write-Verbose` and `Write-Information` are.
|
||||
|
||||
Examples:
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using PSRule.Rules;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Commands
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using PSRule.Annotations;
|
||||
using PSRule.Configuration;
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Rules;
|
||||
|
|
|
@ -297,7 +297,7 @@ namespace PSRule.Pipeline
|
|||
return;
|
||||
}
|
||||
|
||||
DoWriteWarning(string.Format(PSRuleResources.ObjectNotProcessed, TargetName));
|
||||
DoWriteWarning(message: string.Format(PSRuleResources.ObjectNotProcessed, TargetName));
|
||||
}
|
||||
|
||||
public void WarnRuleNotFound()
|
||||
|
@ -307,7 +307,22 @@ namespace PSRule.Pipeline
|
|||
return;
|
||||
}
|
||||
|
||||
DoWriteWarning(PSRuleResources.RuleNotFound);
|
||||
DoWriteWarning(message: PSRuleResources.RuleNotFound);
|
||||
}
|
||||
|
||||
public void ErrorInvaildRuleResult()
|
||||
{
|
||||
if (!_LogError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoWriteError(errorRecord: new ErrorRecord(
|
||||
exception: new RuleRuntimeException(message: string.Format(PSRuleResources.InvalidRuleResult, RuleBlock.RuleId)),
|
||||
errorId: "PSRule.Runtime.InvalidRuleResult",
|
||||
errorCategory: ErrorCategory.InvalidResult,
|
||||
targetObject: null
|
||||
));
|
||||
}
|
||||
|
||||
#endregion Logging
|
||||
|
|
|
@ -60,6 +60,15 @@ namespace PSRule.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An invalid rule result was returned for {0}. Conditions must return boolean $True or $False..
|
||||
/// </summary>
|
||||
internal static string InvalidRuleResult {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidRuleResult", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Target object '{0}' has not been processed because no matching rules were found..
|
||||
/// </summary>
|
||||
|
|
|
@ -117,6 +117,9 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="InvalidRuleResult" xml:space="preserve">
|
||||
<value>An invalid rule result was returned for {0}. Conditions must return boolean $True or $False.</value>
|
||||
</data>
|
||||
<data name="ObjectNotProcessed" xml:space="preserve">
|
||||
<value>Target object '{0}' has not been processed because no matching rules were found.</value>
|
||||
</data>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using PSRule.Pipeline;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Rules
|
||||
|
@ -38,11 +39,14 @@ namespace PSRule.Rules
|
|||
{
|
||||
count++;
|
||||
|
||||
if (v is bool && (bool)v)
|
||||
if (!TryBoolean(v, out bool bresult))
|
||||
{
|
||||
pass++;
|
||||
PipelineContext.CurrentThread.ErrorInvaildRuleResult();
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (v is PSObject && (bool)((PSObject)v).BaseObject)
|
||||
|
||||
if (bresult)
|
||||
{
|
||||
pass++;
|
||||
}
|
||||
|
@ -50,5 +54,29 @@ namespace PSRule.Rules
|
|||
|
||||
return new RuleConditionResult(pass: pass, count: count);
|
||||
}
|
||||
|
||||
private static bool TryBoolean(object o, out bool result)
|
||||
{
|
||||
result = false;
|
||||
|
||||
if (o == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (o is bool bresult)
|
||||
{
|
||||
result = bresult;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o is PSObject pso && pso.BaseObject is bool psoresult)
|
||||
{
|
||||
result = psoresult;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Pester unit test rules for error handling
|
||||
#
|
||||
|
||||
# Synopsis: Should fail
|
||||
Rule 'WithNonBoolean' {
|
||||
$True
|
||||
'false' # Not a boolean
|
||||
}
|
|
@ -1092,3 +1092,26 @@ Describe 'Get-PSRuleHelp' -Tag 'Get-PSRuleHelp', 'Common' {
|
|||
}
|
||||
|
||||
#endregion Get-PSRuleHelp
|
||||
|
||||
#region Rule processing
|
||||
|
||||
Describe 'Rule processing' -Tag 'Common', 'RuleProcessing' {
|
||||
Context 'Error handling' {
|
||||
$ruleFilePath = (Join-Path -Path $here -ChildPath 'FromFileWithError.Rule.ps1');
|
||||
$testObject = [PSCustomObject]@{
|
||||
Name = 'TestObject1'
|
||||
Value = 1
|
||||
}
|
||||
|
||||
It 'Handles non-boolean results' {
|
||||
$result = $testObject | Invoke-PSRule -Path $ruleFilePath -ErrorVariable outError -ErrorAction SilentlyContinue;
|
||||
$messages = @($outError);
|
||||
$result | Should -Not -BeNullOrEmpty;
|
||||
$result.IsSuccess() | Should -Be $False;
|
||||
$messages.Length | Should -BeGreaterThan 0;
|
||||
$messages.Exception.Message | Should -BeLike 'An invalid rule result was returned for *';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Rule processing
|
||||
|
|
Загрузка…
Ссылка в новой задаче