diff --git a/README.md b/README.md
index bc6e700bdc..b3447b6b8c 100644
--- a/README.md
+++ b/README.md
@@ -331,6 +331,7 @@ The following conceptual topics exist in the `PSRule` module:
- [Logging.RuleFail](docs/concepts/PSRule/en-US/about_PSRule_Options.md#loggingrulefail)
- [Logging.RulePass](docs/concepts/PSRule/en-US/about_PSRule_Options.md#loggingrulepass)
- [Output.As](docs/concepts/PSRule/en-US/about_PSRule_Options.md#outputas)
+ - [Output.Banner](docs/concepts/PSRule/en-US/about_PSRule_Options.md#outputbanner)
- [Output.Culture](docs/concepts/PSRule/en-US/about_PSRule_Options.md#outputculture)
- [Output.Encoding](docs/concepts/PSRule/en-US/about_PSRule_Options.md#outputencoding)
- [Output.Format](docs/concepts/PSRule/en-US/about_PSRule_Options.md#outputformat)
diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md
index 9898e33ceb..d6e1062d64 100644
--- a/docs/CHANGELOG-v1.md
+++ b/docs/CHANGELOG-v1.md
@@ -10,6 +10,11 @@ See [upgrade notes][upgrade-notes] for helpful information when upgrading from p
## Unreleased
+What's changed since v1.3.0:
+
+- General improvements:
+ - PSRule banner can be configured in output when using `Assert-PSRule`. [#708](https://github.com/microsoft/PSRule/issues/708)
+
## v1.3.0
What's changed since v1.2.0:
diff --git a/docs/concepts/PSRule/en-US/about_PSRule_Options.md b/docs/concepts/PSRule/en-US/about_PSRule_Options.md
index bfafb943fc..809aa1ab16 100644
--- a/docs/concepts/PSRule/en-US/about_PSRule_Options.md
+++ b/docs/concepts/PSRule/en-US/about_PSRule_Options.md
@@ -27,6 +27,7 @@ The following workspace options are available for use:
- [Logging.RuleFail](#loggingrulefail)
- [Logging.RulePass](#loggingrulepass)
- [Output.As](#outputas)
+- [Output.Banner](#outputbanner)
- [Output.Culture](#outputculture)
- [Output.Encoding](#outputencoding)
- [Output.Format](#outputformat)
@@ -1305,6 +1306,68 @@ variables:
value: Summary
```
+### Output.Banner
+
+The information displayed for PSRule banner.
+This option is only applicable when using `Assert-PSRule` cmdlet.
+
+The following information can be shown or hidden by configuring this option.
+
+- `Title` (1) - Shows the PSRule title ASCII text.
+- `Source` (2) - Shows rules module versions used in this run.
+- `SupportLinks` (4) - Shows supporting links for PSRule and rules modules.
+
+Additionally the following rollup options exist:
+
+- `Default` - Shows `Title`, `Source`, and `SupportLinks`.
+This is the default option.
+- `Minimal` - Shows `Source`.
+
+This option can be configured using one of the named values described above.
+Alternatively, this value can be configured by specifying a bit mask as an integer.
+For example `6` would show `Source`, and `SupportLinks`.
+
+This option can be specified using:
+
+```powershell
+# PowerShell: Using the OutputBanner parameter
+$option = New-PSRuleOption -OutputBanner Minimal;
+```
+
+```powershell
+# PowerShell: Using the Output.Banner hashtable key
+$option = New-PSRuleOption -Option @{ 'Output.Banner' = 'Minimal' };
+```
+
+```powershell
+# PowerShell: Using the OutputBanner parameter to set YAML
+Set-PSRuleOption -OutputBanner Minimal;
+```
+
+```yaml
+# YAML: Using the output/banner property
+output:
+ banner: OutputBanner
+```
+
+```bash
+# Bash: Using environment variable
+export PSRULE_OUTPUT_BANNER=Minimal
+```
+
+```yaml
+# GitHub Actions: Using environment variable
+env:
+ PSRULE_OUTPUT_BANNER: Minimal
+```
+
+```yaml
+# Azure Pipelines: Using environment variable
+variables:
+- name: PSRULE_OUTPUT_BANNER
+ value: Minimal
+```
+
### Output.Culture
Specified the name of one or more cultures to use for generating output.
@@ -1907,6 +1970,7 @@ logging:
output:
as: Summary
+ banner: Minimal
culture:
- en-US
encoding: UTF8
@@ -1993,6 +2057,7 @@ logging:
output:
as: Detail
+ banner: Default
culture: [ ]
encoding: Default
format: None
diff --git a/schemas/PSRule-options.schema.json b/schemas/PSRule-options.schema.json
index 26d9ae552a..97d8044c8c 100644
--- a/schemas/PSRule-options.schema.json
+++ b/schemas/PSRule-options.schema.json
@@ -312,6 +312,28 @@
],
"default": "Detail"
},
+ "banner": {
+ "title": "Banner format",
+ "description": "The information displayed for Assert-PSRule banner. The default is Default which includes Title, Source, and SupportLinks.",
+ "markdownDescription": "The information displayed for Assert-PSRule banner. The default is `Default` which includes `Title`, `Source`, and `SupportLinks`. [See help](https://microsoft.github.io/PSRule/concepts/PSRule/en-US/about_PSRule_Options.html#outputbanner)",
+ "oneOf": [
+ {
+ "type": "string",
+ "enum": [
+ "None",
+ "Title",
+ "Source",
+ "SupportLinks",
+ "Default",
+ "Minimal"
+ ]
+ },
+ {
+ "type": "integer"
+ }
+ ],
+ "default": "Default"
+ },
"culture": {
"type": "array",
"title": "Culture",
diff --git a/src/PSRule/Configuration/BannerFormat.cs b/src/PSRule/Configuration/BannerFormat.cs
new file mode 100644
index 0000000000..140e2366fe
--- /dev/null
+++ b/src/PSRule/Configuration/BannerFormat.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using System;
+
+namespace PSRule.Configuration
+{
+ ///
+ /// The information displayed for Assert-PSRule banner.
+ ///
+ [Flags]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public enum BannerFormat
+ {
+ ///
+ /// No banner is shown.
+ ///
+ None = 0,
+
+ ///
+ /// The PSRule title ASCII text is shown.
+ ///
+ Title = 1,
+
+ ///
+ /// The rules module versions used in this run are shown.
+ ///
+ Source = 2,
+
+ ///
+ /// Supporting links for PSRule and rules modules are shown.
+ ///
+ SupportLinks = 4,
+
+ Default = Title | Source | SupportLinks,
+ Minimal = Source
+ }
+}
diff --git a/src/PSRule/Configuration/OutputOption.cs b/src/PSRule/Configuration/OutputOption.cs
index 6d62c1b57f..09ebe85fa0 100644
--- a/src/PSRule/Configuration/OutputOption.cs
+++ b/src/PSRule/Configuration/OutputOption.cs
@@ -18,10 +18,12 @@ public sealed class OutputOption : IEquatable
private const OutputFormat DEFAULT_FORMAT = OutputFormat.None;
private const RuleOutcome DEFAULT_OUTCOME = RuleOutcome.Processed;
private const OutputStyle DEFAULT_STYLE = OutputStyle.Client;
+ private const BannerFormat DEFAULT_BANNER = BannerFormat.Default;
internal static readonly OutputOption Default = new OutputOption
{
As = DEFAULT_AS,
+ Banner = DEFAULT_BANNER,
Encoding = DEFAULT_ENCODING,
Format = DEFAULT_FORMAT,
Outcome = DEFAULT_OUTCOME,
@@ -31,6 +33,7 @@ public sealed class OutputOption : IEquatable
public OutputOption()
{
As = null;
+ Banner = null;
Culture = null;
Encoding = null;
Format = null;
@@ -44,6 +47,7 @@ public OutputOption(OutputOption option)
return;
As = option.As;
+ Banner = option.Banner;
Culture = option.Culture;
Encoding = option.Encoding;
Format = option.Format;
@@ -61,6 +65,7 @@ public bool Equals(OutputOption other)
{
return other != null &&
As == other.As &&
+ Banner == other.Banner &&
Culture == other.Culture &&
Encoding == other.Encoding &&
Format == other.Format &&
@@ -75,6 +80,7 @@ public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + (As.HasValue ? As.Value.GetHashCode() : 0);
+ hash = hash * 23 + (Banner.HasValue ? Banner.Value.GetHashCode() : 0);
hash = hash * 23 + (Culture != null ? Culture.GetHashCode() : 0);
hash = hash * 23 + (Encoding.HasValue ? Encoding.Value.GetHashCode() : 0);
hash = hash * 23 + (Format.HasValue ? Format.Value.GetHashCode() : 0);
@@ -90,6 +96,7 @@ internal static OutputOption Combine(OutputOption o1, OutputOption o2)
var result = new OutputOption(o1)
{
As = o1.As ?? o2.As,
+ Banner = o1.Banner ?? o2.Banner,
Culture = o1.Culture ?? o2.Culture,
Encoding = o1.Encoding ?? o2.Encoding,
Format = o1.Format ?? o2.Format,
@@ -106,6 +113,15 @@ internal static OutputOption Combine(OutputOption o1, OutputOption o2)
[DefaultValue(null)]
public ResultFormat? As { get; set; }
+ ///
+ /// The information displayed for Assert-PSRule banner.
+ ///
+ [DefaultValue(null)]
+ public BannerFormat? Banner { get; set; }
+
+ ///
+ /// One or more cultures to use for generating output.
+ ///
[DefaultValue(null)]
public string[] Culture { get; set; }
@@ -121,6 +137,9 @@ internal static OutputOption Combine(OutputOption o1, OutputOption o2)
[DefaultValue(null)]
public OutputFormat? Format { get; set; }
+ ///
+ /// The outcome of rule results to return.
+ ///
[DefaultValue(null)]
public RuleOutcome? Outcome { get; set; }
@@ -130,6 +149,9 @@ internal static OutputOption Combine(OutputOption o1, OutputOption o2)
[DefaultValue(null)]
public string Path { get; set; }
+ ///
+ /// The style that results will be presented in.
+ ///
[DefaultValue(null)]
public OutputStyle? Style { get; set; }
@@ -138,6 +160,9 @@ internal void Load(EnvironmentHelper env)
if (env.TryEnum("PSRULE_OUTPUT_AS", out ResultFormat value))
As = value;
+ if (env.TryEnum("PSRULE_OUTPUT_BANNER", out BannerFormat banner))
+ Banner = banner;
+
if (env.TryStringArray("PSRULE_OUTPUT_CULTURE", out string[] culture))
Culture = culture;
@@ -162,6 +187,9 @@ internal void Load(Dictionary index)
if (index.TryPopEnum("Output.As", out ResultFormat value))
As = value;
+ if (index.TryPopEnum("Output.Banner", out BannerFormat banner))
+ Banner = banner;
+
if (index.TryPopStringArray("Output.Culture", out string[] culture))
Culture = culture;
diff --git a/src/PSRule/PSRule.psm1 b/src/PSRule/PSRule.psm1
index 2623a6c918..52f87a8bc3 100644
--- a/src/PSRule/PSRule.psm1
+++ b/src/PSRule/PSRule.psm1
@@ -1108,6 +1108,11 @@ function New-PSRuleOption {
[ValidateSet('Detail', 'Summary')]
[PSRule.Configuration.ResultFormat]$OutputAs = 'Detail',
+ # Sets the Output.Banner option
+ [Parameter(Mandatory = $False)]
+ [ValidateSet('Default', 'Minimal', 'None', 'Title', 'Source', 'SupportLinks')]
+ [PSRule.Configuration.BannerFormat]$OutputBanner = 'Default',
+
# Sets the Output.Culture option
[Parameter(Mandatory = $False)]
[String[]]$OutputCulture,
@@ -1323,6 +1328,11 @@ function Set-PSRuleOption {
[ValidateSet('Detail', 'Summary')]
[PSRule.Configuration.ResultFormat]$OutputAs = 'Detail',
+ # Sets the Output.Banner option
+ [Parameter(Mandatory = $False)]
+ [ValidateSet('Default', 'Minimal', 'None', 'Title', 'Source', 'SupportLinks')]
+ [PSRule.Configuration.BannerFormat]$OutputBanner = 'Default',
+
# Sets the Output.Culture option
[Parameter(Mandatory = $False)]
[String[]]$OutputCulture,
@@ -1948,6 +1958,11 @@ function SetOptions {
[ValidateSet('Detail', 'Summary')]
[PSRule.Configuration.ResultFormat]$OutputAs = 'Detail',
+ # Sets the Output.Banner option
+ [Parameter(Mandatory = $False)]
+ [ValidateSet('Default', 'Minimal', 'None', 'Title', 'Source', 'SupportLinks')]
+ [PSRule.Configuration.BannerFormat]$OutputBanner = 'Default',
+
# Sets the Output.Culture option
[Parameter(Mandatory = $False)]
[String[]]$OutputCulture,
@@ -2080,6 +2095,11 @@ function SetOptions {
$Option.Output.As = $OutputAs;
}
+ # Sets option Output.As
+ if ($PSBoundParameters.ContainsKey('OutputBanner')) {
+ $Option.Output.Banner = $OutputBanner;
+ }
+
# Sets option Output.Culture
if ($PSBoundParameters.ContainsKey('OutputCulture')) {
$Option.Output.Culture = $OutputCulture;
diff --git a/src/PSRule/Pipeline/AssertPipeline.cs b/src/PSRule/Pipeline/AssertPipeline.cs
index dd87d2ab87..d3bc7b5be3 100644
--- a/src/PSRule/Pipeline/AssertPipeline.cs
+++ b/src/PSRule/Pipeline/AssertPipeline.cs
@@ -93,7 +93,7 @@ protected AssertFormatterBase(Source[] source, IPipelineWriter writer, PSRuleOpt
Option = option;
Banner();
Source(source);
- Help(source);
+ SupportLinks(source);
}
public void Error(ErrorRecord errorRecord)
@@ -185,6 +185,9 @@ protected virtual void Warning(string message)
protected void Banner()
{
+ if (!Option.Output.Banner.GetValueOrDefault(BannerFormat.Default).HasFlag(BannerFormat.Title))
+ return;
+
WriteLine(FormatterStrings.Banner.Replace("\\n", Environment.NewLine));
LineBreak();
}
@@ -203,6 +206,9 @@ protected void StartObject(InvokeResult result, out RuleRecord[] records, Consol
private void Source(Source[] source)
{
+ if (!Option.Output.Banner.GetValueOrDefault(BannerFormat.Default).HasFlag(BannerFormat.Source))
+ return;
+
var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;
WriteLineFormat(FormatterStrings.PSRuleVersion, version);
var list = new HashSet(StringComparer.OrdinalIgnoreCase);
@@ -217,8 +223,11 @@ private void Source(Source[] source)
LineBreak();
}
- private void Help(Source[] source)
+ private void SupportLinks(Source[] source)
{
+ if (!Option.Output.Banner.GetValueOrDefault(BannerFormat.Default).HasFlag(BannerFormat.SupportLinks))
+ return;
+
WriteLine(OUTPUT_SEPARATOR_BAR);
WriteLine(FormatterStrings.HelpDocs);
WriteLine(FormatterStrings.HelpContribute);
diff --git a/src/PSRule/Pipeline/PipelineBuilder.cs b/src/PSRule/Pipeline/PipelineBuilder.cs
index f57705803b..486c261826 100644
--- a/src/PSRule/Pipeline/PipelineBuilder.cs
+++ b/src/PSRule/Pipeline/PipelineBuilder.cs
@@ -168,6 +168,7 @@ public virtual IPipelineBuilder Configure(PSRuleOption option)
Option.Input.Format = Option.Input.Format ?? InputOption.Default.Format;
Option.Output = new OutputOption(option.Output);
Option.Output.Outcome = Option.Output.Outcome ?? OutputOption.Default.Outcome;
+ Option.Output.Banner = Option.Output.Banner ?? OutputOption.Default.Banner;
return this;
}
diff --git a/tests/PSRule.Tests/PSRule.Options.Tests.ps1 b/tests/PSRule.Tests/PSRule.Options.Tests.ps1
index d53534bbed..6b2998e2fb 100644
--- a/tests/PSRule.Tests/PSRule.Options.Tests.ps1
+++ b/tests/PSRule.Tests/PSRule.Options.Tests.ps1
@@ -974,6 +974,45 @@ Describe 'New-PSRuleOption' -Tag 'Option','New-PSRuleOption' {
}
}
+ Context 'Read Output.Banner' {
+ It 'from default' {
+ $option = New-PSRuleOption -Default;
+ $option.Output.Banner | Should -Be 'Default';
+ }
+
+ It 'from Hashtable' {
+ $option = New-PSRuleOption -Option @{ 'Output.Banner' = 'Minimal' };
+ $option.Output.Banner | Should -Be 'Minimal';
+
+ $option = New-PSRuleOption -Option @{ 'Output.Banner' = 1 };
+ $option.Output.Banner | Should -Be 'Title';
+ }
+
+ It 'from YAML' {
+ $option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests.yml');
+ $option.Output.Banner | Should -Be 'Minimal';
+
+ $option = New-PSRuleOption -Option (Join-Path -Path $here -ChildPath 'PSRule.Tests2.yml');
+ $option.Output.Banner | Should -Be 'Title';
+ }
+
+ It 'from Environment' {
+ try {
+ $Env:PSRULE_OUTPUT_BANNER = 'Minimal';
+ $option = New-PSRuleOption;
+ $option.Output.Banner | Should -Be 'Minimal';
+ }
+ finally {
+ Remove-Item 'Env:PSRULE_OUTPUT_BANNER' -Force;
+ }
+ }
+
+ It 'from parameter' {
+ $option = New-PSRuleOption -OutputBanner 'Minimal' -Path $emptyOptionsFilePath;
+ $option.Output.Banner | Should -Be 'Minimal';
+ }
+ }
+
Context 'Read Output.Culture' {
It 'from default' {
$option = New-PSRuleOption -Default;
@@ -1447,6 +1486,13 @@ Describe 'Set-PSRuleOption' -Tag 'Option','Set-PSRuleOption' {
}
}
+ Context 'Read Output.Banner' {
+ It 'from parameter' {
+ $option = Set-PSRuleOption -OutputBanner 'Minimal' @optionParams;
+ $option.Output.Banner | Should -Be 'Minimal';
+ }
+ }
+
Context 'Read Output.Culture' {
It 'from parameter' {
# Single
diff --git a/tests/PSRule.Tests/PSRule.Tests.yml b/tests/PSRule.Tests/PSRule.Tests.yml
index a3603b42b3..470f1039a3 100644
--- a/tests/PSRule.Tests/PSRule.Tests.yml
+++ b/tests/PSRule.Tests/PSRule.Tests.yml
@@ -62,6 +62,7 @@ logging:
# Configure output options
output:
as: Summary
+ banner: Minimal
culture: [ 'en-CC' ]
encoding: UTF7
format: Json
diff --git a/tests/PSRule.Tests/PSRule.Tests2.yml b/tests/PSRule.Tests/PSRule.Tests2.yml
index 37118cc2e2..5298583a4a 100644
--- a/tests/PSRule.Tests/PSRule.Tests2.yml
+++ b/tests/PSRule.Tests/PSRule.Tests2.yml
@@ -23,6 +23,7 @@ input:
# Configure output
output:
+ banner: 1
culture:
- 'en-CC'
- 'en-DD'