diff --git a/Engine/Commands/InvokeScriptAnalyzerCommand.cs b/Engine/Commands/InvokeScriptAnalyzerCommand.cs
index 936d38925..7e552fc9e 100644
--- a/Engine/Commands/InvokeScriptAnalyzerCommand.cs
+++ b/Engine/Commands/InvokeScriptAnalyzerCommand.cs
@@ -169,17 +169,18 @@ public SwitchParameter SuppressedOnly
private bool suppressedOnly;
///
- /// Returns path to the file that contains user profile for ScriptAnalyzer
+ /// Returns path to the file that contains user profile or hash table for ScriptAnalyzer
///
[Alias("Profile")]
[Parameter(Mandatory = false)]
[ValidateNotNull]
- public string Configuration
+ public object Settings
{
- get { return configuration; }
- set { configuration = value; }
+ get { return settings; }
+ set { settings = value; }
}
- private string configuration;
+
+ private object settings;
private bool stopProcessing;
@@ -195,7 +196,7 @@ protected override void BeginProcessing()
string[] rulePaths = Helper.ProcessCustomRulePaths(customRulePath,
this.SessionState, recurseCustomRulePath);
- if (!ScriptAnalyzer.Instance.ParseProfile(this.configuration, this.SessionState.Path, this))
+ if (!ScriptAnalyzer.Instance.ParseProfile(this.settings, this.SessionState.Path, this))
{
stopProcessing = true;
return;
@@ -208,8 +209,7 @@ protected override void BeginProcessing()
this.excludeRule,
this.severity,
null == rulePaths ? true : this.includeDefaultRules,
- this.suppressedOnly,
- this.configuration);
+ this.suppressedOnly);
}
///
@@ -238,6 +238,18 @@ protected override void ProcessRecord()
}
}
+ protected override void EndProcessing()
+ {
+ ScriptAnalyzer.Instance.CleanUp();
+ base.EndProcessing();
+ }
+
+ protected override void StopProcessing()
+ {
+ ScriptAnalyzer.Instance.CleanUp();
+ base.StopProcessing();
+ }
+
#endregion
#region Methods
diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs
index e9241770d..b37fe099d 100644
--- a/Engine/ScriptAnalyzer.cs
+++ b/Engine/ScriptAnalyzer.cs
@@ -27,6 +27,7 @@
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
+using System.Collections;
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
{
@@ -101,8 +102,7 @@ internal void Initialize(
string[] excludeRuleNames = null,
string[] severity = null,
bool includeDefaultRules = false,
- bool suppressedOnly = false,
- string profile = null)
+ bool suppressedOnly = false)
where TCmdlet : PSCmdlet, IOutputWriter
{
if (cmdlet == null)
@@ -119,8 +119,7 @@ internal void Initialize(
excludeRuleNames,
severity,
includeDefaultRules,
- suppressedOnly,
- profile);
+ suppressedOnly);
}
///
@@ -134,8 +133,7 @@ public void Initialize(
string[] excludeRuleNames = null,
string[] severity = null,
bool includeDefaultRules = false,
- bool suppressedOnly = false,
- string profile = null)
+ bool suppressedOnly = false)
{
if (runspace == null)
{
@@ -151,161 +149,304 @@ public void Initialize(
excludeRuleNames,
severity,
includeDefaultRules,
- suppressedOnly,
- profile);
+ suppressedOnly);
}
- internal bool ParseProfile(string profile, PathIntrinsics path, IOutputWriter writer)
+ ///
+ /// clean up this instance, resetting all properties
+ ///
+ public void CleanUp()
{
- IEnumerable includeRuleList = new List();
- IEnumerable excludeRuleList = new List();
- IEnumerable severityList = new List();
+ includeRule = null;
+ excludeRule = null;
+ severity = null;
+ includeRegexList = null;
+ excludeRegexList = null;
+ suppressedOnly = false;
+ }
+
+ internal bool ParseProfile(object profileObject, PathIntrinsics path, IOutputWriter writer)
+ {
+ // profile was not given
+ if (profileObject == null)
+ {
+ return true;
+ }
+
+ if (!(profileObject is string || profileObject is Hashtable))
+ {
+ return false;
+ }
+
+ List includeRuleList = new List();
+ List excludeRuleList = new List();
+ List severityList = new List();
bool hasError = false;
- if (!String.IsNullOrWhiteSpace(profile))
+ Hashtable hashTableProfile = profileObject as Hashtable;
+
+ // checks whether we get a hashtable
+ if (hashTableProfile != null)
{
- try
+ hasError = ParseProfileHashtable(hashTableProfile, path, writer, severityList, includeRuleList, excludeRuleList);
+ }
+ else
+ {
+ // checks whether we get a string instead
+ string profile = profileObject as string;
+
+ if (!String.IsNullOrWhiteSpace(profile))
{
- profile = path.GetResolvedPSPathFromPSPath(profile).First().Path;
+ hasError = ParseProfileString(profile, path, writer, severityList, includeRuleList, excludeRuleList);
}
- catch
+ }
+
+ if (hasError)
+ {
+ return false;
+ }
+
+ this.severity = (severityList.Count() == 0) ? null : severityList.ToArray();
+ this.includeRule = (includeRuleList.Count() == 0) ? null : includeRuleList.ToArray();
+ this.excludeRule = (excludeRuleList.Count() == 0) ? null : excludeRuleList.ToArray();
+
+ return true;
+ }
+
+ private bool ParseProfileHashtable(Hashtable profile, PathIntrinsics path, IOutputWriter writer,
+ List severityList, List includeRuleList, List excludeRuleList)
+ {
+ bool hasError = false;
+
+ HashSet validKeys = new HashSet(StringComparer.OrdinalIgnoreCase);
+ validKeys.Add("severity");
+ validKeys.Add("includerules");
+ validKeys.Add("excluderules");
+
+ foreach (var obj in profile.Keys)
+ {
+ string key = obj as string;
+
+ // key should be a string
+ if (key == null)
{
- writer.WriteError(new ErrorRecord(new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Strings.FileNotFound, profile)),
- Strings.ConfigurationFileNotFound, ErrorCategory.ResourceUnavailable, profile));
+ writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.KeyNotString, key)),
+ Strings.ConfigurationKeyNotAString, ErrorCategory.InvalidData, profile));
hasError = true;
+ continue;
}
- if (File.Exists(profile))
+ // checks whether it falls into list of valid keys
+ if (!validKeys.Contains(key))
{
- Token[] parserTokens = null;
- ParseError[] parserErrors = null;
- Ast profileAst = Parser.ParseFile(profile, out parserTokens, out parserErrors);
- IEnumerable hashTableAsts = profileAst.FindAll(item => item is HashtableAst, false);
+ writer.WriteError(new ErrorRecord(
+ new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongKeyHashTable, key)),
+ Strings.WrongConfigurationKey, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
+ }
- // no hashtable, raise warning
- if (hashTableAsts.Count() == 0)
+ object value = profile[obj];
+
+ // value must be either string or collections of string or array
+ if (value == null || !(value is string || value is IEnumerable || value.GetType().IsArray))
+ {
+ writer.WriteError(new ErrorRecord(
+ new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueHashTable, value, key)),
+ Strings.WrongConfigurationKey, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
+ }
+
+ // if we get here then everything is good
+
+ List values = new List();
+
+ if (value is string)
+ {
+ values.Add(value as string);
+ }
+ else if (value is IEnumerable)
+ {
+ values.Union(value as IEnumerable);
+ }
+ else if (value.GetType().IsArray)
+ {
+ // for array case, sometimes we won't be able to cast it directly to IEnumerable
+ foreach (var val in value as IEnumerable)
{
- writer.WriteError(new ErrorRecord(new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidProfile, profile)),
- Strings.ConfigurationFileHasNoHashTable, ErrorCategory.ResourceUnavailable, profile));
- hasError = true;
+ if (val is string)
+ {
+ values.Add(val as string);
+ }
+ else
+ {
+ writer.WriteError(new ErrorRecord(
+ new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueHashTable, val, key)),
+ Strings.WrongConfigurationKey, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
+ }
}
- else
+ }
+
+ // now add to the list
+ switch (key)
+ {
+ case "severity":
+ severityList.AddRange(values);
+ break;
+ case "includerules":
+ includeRuleList.AddRange(values);
+ break;
+ case "excluderules":
+ excludeRuleList.AddRange(values);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return hasError;
+ }
+
+ private bool ParseProfileString(string profile, PathIntrinsics path, IOutputWriter writer,
+ List severityList, List includeRuleList, List excludeRuleList)
+ {
+ bool hasError = false;
+
+ try
+ {
+ profile = path.GetResolvedPSPathFromPSPath(profile).First().Path;
+ }
+ catch
+ {
+ writer.WriteError(new ErrorRecord(new FileNotFoundException(string.Format(CultureInfo.CurrentCulture, Strings.FileNotFound, profile)),
+ Strings.ConfigurationFileNotFound, ErrorCategory.ResourceUnavailable, profile));
+ hasError = true;
+ }
+
+ if (File.Exists(profile))
+ {
+ Token[] parserTokens = null;
+ ParseError[] parserErrors = null;
+ Ast profileAst = Parser.ParseFile(profile, out parserTokens, out parserErrors);
+ IEnumerable hashTableAsts = profileAst.FindAll(item => item is HashtableAst, false);
+
+ // no hashtable, raise warning
+ if (hashTableAsts.Count() == 0)
+ {
+ writer.WriteError(new ErrorRecord(new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.InvalidProfile, profile)),
+ Strings.ConfigurationFileHasNoHashTable, ErrorCategory.ResourceUnavailable, profile));
+ hasError = true;
+ }
+ else
+ {
+ HashtableAst hashTableAst = hashTableAsts.First() as HashtableAst;
+
+ foreach (var kvp in hashTableAst.KeyValuePairs)
{
- HashtableAst hashTableAst = hashTableAsts.First() as HashtableAst;
+ if (!(kvp.Item1 is StringConstantExpressionAst))
+ {
+ // first item (the key) should be a string
+ writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongKeyFormat, kvp.Item1.Extent.StartLineNumber, kvp.Item1.Extent.StartColumnNumber, profile)),
+ Strings.ConfigurationKeyNotAString, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
+ }
- foreach (var kvp in hashTableAst.KeyValuePairs)
+ // parse the item2 as array
+ PipelineAst pipeAst = kvp.Item2 as PipelineAst;
+ List rhsList = new List();
+ if (pipeAst != null)
{
- if (!(kvp.Item1 is StringConstantExpressionAst))
+ ExpressionAst pureExp = pipeAst.GetPureExpression();
+ if (pureExp is StringConstantExpressionAst)
{
- // first item (the key) should be a string
- writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongKeyFormat, kvp.Item1.Extent.StartLineNumber, kvp.Item1.Extent.StartColumnNumber, profile)),
- Strings.ConfigurationKeyNotAString, ErrorCategory.InvalidData, profile));
- hasError = true;
- continue;
+ rhsList.Add((pureExp as StringConstantExpressionAst).Value);
}
-
- // parse the item2 as array
- PipelineAst pipeAst = kvp.Item2 as PipelineAst;
- List rhsList = new List();
- if (pipeAst != null)
+ else
{
- ExpressionAst pureExp = pipeAst.GetPureExpression();
- if (pureExp is StringConstantExpressionAst)
- {
- rhsList.Add((pureExp as StringConstantExpressionAst).Value);
- }
- else
+ ArrayLiteralAst arrayLitAst = pureExp as ArrayLiteralAst;
+ if (arrayLitAst == null && pureExp is ArrayExpressionAst)
{
- ArrayLiteralAst arrayLitAst = pureExp as ArrayLiteralAst;
- if (arrayLitAst == null && pureExp is ArrayExpressionAst)
+ ArrayExpressionAst arrayExp = pureExp as ArrayExpressionAst;
+ // Statements property is never null
+ if (arrayExp.SubExpression != null)
{
- ArrayExpressionAst arrayExp = pureExp as ArrayExpressionAst;
- // Statements property is never null
- if (arrayExp.SubExpression != null)
+ StatementAst stateAst = arrayExp.SubExpression.Statements.FirstOrDefault();
+ if (stateAst != null && stateAst is PipelineAst)
{
- StatementAst stateAst = arrayExp.SubExpression.Statements.FirstOrDefault();
- if (stateAst != null && stateAst is PipelineAst)
+ CommandBaseAst cmdBaseAst = (stateAst as PipelineAst).PipelineElements.FirstOrDefault();
+ if (cmdBaseAst != null && cmdBaseAst is CommandExpressionAst)
{
- CommandBaseAst cmdBaseAst = (stateAst as PipelineAst).PipelineElements.FirstOrDefault();
- if (cmdBaseAst != null && cmdBaseAst is CommandExpressionAst)
+ CommandExpressionAst cmdExpAst = cmdBaseAst as CommandExpressionAst;
+ if (cmdExpAst.Expression is StringConstantExpressionAst)
{
- CommandExpressionAst cmdExpAst = cmdBaseAst as CommandExpressionAst;
- if (cmdExpAst.Expression is StringConstantExpressionAst)
- {
- rhsList.Add((cmdExpAst.Expression as StringConstantExpressionAst).Value);
- }
- else
- {
- arrayLitAst = cmdExpAst.Expression as ArrayLiteralAst;
- }
+ rhsList.Add((cmdExpAst.Expression as StringConstantExpressionAst).Value);
+ }
+ else
+ {
+ arrayLitAst = cmdExpAst.Expression as ArrayLiteralAst;
}
}
}
}
+ }
- if (arrayLitAst != null)
+ if (arrayLitAst != null)
+ {
+ foreach (var element in arrayLitAst.Elements)
{
- foreach (var element in arrayLitAst.Elements)
+ // all the values in the array needs to be string
+ if (!(element is StringConstantExpressionAst))
{
- // all the values in the array needs to be string
- if (!(element is StringConstantExpressionAst))
- {
- writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueFormat, element.Extent.StartLineNumber, element.Extent.StartColumnNumber, profile)),
- Strings.ConfigurationValueNotAString, ErrorCategory.InvalidData, profile));
- hasError = true;
- continue;
- }
-
- rhsList.Add((element as StringConstantExpressionAst).Value);
+ writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueFormat, element.Extent.StartLineNumber, element.Extent.StartColumnNumber, profile)),
+ Strings.ConfigurationValueNotAString, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
}
+
+ rhsList.Add((element as StringConstantExpressionAst).Value);
}
}
}
+ }
- if (rhsList.Count == 0)
- {
- writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueFormat, kvp.Item2.Extent.StartLineNumber, kvp.Item2.Extent.StartColumnNumber, profile)),
- Strings.ConfigurationValueWrongFormat, ErrorCategory.InvalidData, profile));
- hasError = true;
- continue;
- }
+ if (rhsList.Count == 0)
+ {
+ writer.WriteError(new ErrorRecord(new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongValueFormat, kvp.Item2.Extent.StartLineNumber, kvp.Item2.Extent.StartColumnNumber, profile)),
+ Strings.ConfigurationValueWrongFormat, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ continue;
+ }
- string key = (kvp.Item1 as StringConstantExpressionAst).Value.ToLower();
+ string key = (kvp.Item1 as StringConstantExpressionAst).Value.ToLower();
- switch (key)
- {
- case "severity":
- severityList = severityList.Union(rhsList);
- break;
- case "includerules":
- includeRuleList = includeRuleList.Union(rhsList);
- break;
- case "excluderules":
- excludeRuleList = excludeRuleList.Union(rhsList);
- break;
- default:
- writer.WriteError(new ErrorRecord(
- new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongKey, key, kvp.Item1.Extent.StartLineNumber, kvp.Item1.Extent.StartColumnNumber, profile)),
- Strings.WrongConfigurationKey, ErrorCategory.InvalidData, profile));
- hasError = true;
- break;
- }
+ switch (key)
+ {
+ case "severity":
+ severityList.AddRange(rhsList);
+ break;
+ case "includerules":
+ includeRuleList.AddRange(rhsList);
+ break;
+ case "excluderules":
+ excludeRuleList.AddRange(rhsList);
+ break;
+ default:
+ writer.WriteError(new ErrorRecord(
+ new InvalidDataException(string.Format(CultureInfo.CurrentCulture, Strings.WrongKey, key, kvp.Item1.Extent.StartLineNumber, kvp.Item1.Extent.StartColumnNumber, profile)),
+ Strings.WrongConfigurationKey, ErrorCategory.InvalidData, profile));
+ hasError = true;
+ break;
}
}
}
}
- if (hasError)
- {
- return false;
- }
-
- this.severity = (severityList.Count() == 0) ? null : severityList.ToArray();
- this.includeRule = (includeRuleList.Count() == 0) ? null : includeRuleList.ToArray();
- this.excludeRule = (excludeRuleList.Count() == 0) ? null : excludeRuleList.ToArray();
-
- return true;
+ return hasError;
}
private void Initialize(
diff --git a/Engine/Strings.Designer.cs b/Engine/Strings.Designer.cs
index 0f5dc9d0a..379b35d13 100644
--- a/Engine/Strings.Designer.cs
+++ b/Engine/Strings.Designer.cs
@@ -88,7 +88,7 @@ internal static string CommandInfoNotFound {
}
///
- /// Looks up a localized string similar to ConfigurationFileHasNoHashTable.
+ /// Looks up a localized string similar to SettingsFileHasNoHashTable.
///
internal static string ConfigurationFileHasNoHashTable {
get {
@@ -97,7 +97,7 @@ internal static string ConfigurationFileHasNoHashTable {
}
///
- /// Looks up a localized string similar to ConfigurationFileNotFound.
+ /// Looks up a localized string similar to SettingsFileNotFound.
///
internal static string ConfigurationFileNotFound {
get {
@@ -106,7 +106,7 @@ internal static string ConfigurationFileNotFound {
}
///
- /// Looks up a localized string similar to ConfigurationKeyNotAString.
+ /// Looks up a localized string similar to SettingsKeyNotAString.
///
internal static string ConfigurationKeyNotAString {
get {
@@ -115,7 +115,7 @@ internal static string ConfigurationKeyNotAString {
}
///
- /// Looks up a localized string similar to ConfigurationValueNotAString.
+ /// Looks up a localized string similar to SettingsValueNotAString.
///
internal static string ConfigurationValueNotAString {
get {
@@ -124,7 +124,7 @@ internal static string ConfigurationValueNotAString {
}
///
- /// Looks up a localized string similar to ConfigurationValueWrongFormat.
+ /// Looks up a localized string similar to SettingsValueWrongFormat.
///
internal static string ConfigurationValueWrongFormat {
get {
@@ -169,7 +169,7 @@ internal static string InvalidPath {
}
///
- /// Looks up a localized string similar to Profile file '{0}' is invalid because it does not contain a hashtable..
+ /// Looks up a localized string similar to Settings file '{0}' is invalid because it does not contain a hashtable..
///
internal static string InvalidProfile {
get {
@@ -177,6 +177,15 @@ internal static string InvalidProfile {
}
}
+ ///
+ /// Looks up a localized string similar to Key {0} in the settings is not a string..
+ ///
+ internal static string KeyNotString {
+ get {
+ return ResourceManager.GetString("KeyNotString", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to No loggers found..
///
@@ -367,7 +376,7 @@ internal static string VerboseScriptDefinitionMessage {
}
///
- /// Looks up a localized string similar to WrongConfigurationKey.
+ /// Looks up a localized string similar to WrongSettingsKey.
///
internal static string WrongConfigurationKey {
get {
@@ -376,7 +385,7 @@ internal static string WrongConfigurationKey {
}
///
- /// Looks up a localized string similar to {0} is not a valid key in the profile hashtable: line {1} column {2} in file {3}. Valid keys are ExcludeRules, IncludeRules and Severity..
+ /// Looks up a localized string similar to {0} is not a valid key in the settings hashtable: line {1} column {2} in file {3}. Valid keys are ExcludeRules, IncludeRules and Severity..
///
internal static string WrongKey {
get {
@@ -385,7 +394,7 @@ internal static string WrongKey {
}
///
- /// Looks up a localized string similar to Key in the profile hashtable should be a string: line {0} column {1} in file {2}.
+ /// Looks up a localized string similar to Key in the settings hashtable should be a string: line {0} column {1} in file {2}.
///
internal static string WrongKeyFormat {
get {
@@ -393,6 +402,15 @@ internal static string WrongKeyFormat {
}
}
+ ///
+ /// Looks up a localized string similar to {0} is not a valid key in the settings hashtable. Valid keys are ExcludeRules, IncludeRules and Severity..
+ ///
+ internal static string WrongKeyHashTable {
+ get {
+ return ResourceManager.GetString("WrongKeyHashTable", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Scope can only be either function or class..
///
@@ -403,12 +421,21 @@ internal static string WrongScopeArgumentSuppressionAttributeError {
}
///
- /// Looks up a localized string similar to Value in the profile hashtable should be a string or an array of strings: line {0} column {1} in file {2}.
+ /// Looks up a localized string similar to Value in the settings hashtable should be a string or an array of strings: line {0} column {1} in file {2}.
///
internal static string WrongValueFormat {
get {
return ResourceManager.GetString("WrongValueFormat", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to Value {0} for key {1} has the wrong data type. Value in the settings hashtable should be a string or an array of strings..
+ ///
+ internal static string WrongValueHashTable {
+ get {
+ return ResourceManager.GetString("WrongValueHashTable", resourceCulture);
+ }
+ }
}
}
diff --git a/Engine/Strings.resx b/Engine/Strings.resx
index 2707a02be..aa1a3f779 100644
--- a/Engine/Strings.resx
+++ b/Engine/Strings.resx
@@ -193,16 +193,16 @@
Cannot find any DiagnosticRecord with the Rule Suppression ID {0}.
- {0} is not a valid key in the profile hashtable: line {1} column {2} in file {3}. Valid keys are ExcludeRules, IncludeRules and Severity.
+ {0} is not a valid key in the settings hashtable: line {1} column {2} in file {3}. Valid keys are ExcludeRules, IncludeRules and Severity.
- Key in the profile hashtable should be a string: line {0} column {1} in file {2}
+ Key in the settings hashtable should be a string: line {0} column {1} in file {2}
- Value in the profile hashtable should be a string or an array of strings: line {0} column {1} in file {2}
+ Value in the settings hashtable should be a string or an array of strings: line {0} column {1} in file {2}
- Profile file '{0}' is invalid because it does not contain a hashtable.
+ Settings file '{0}' is invalid because it does not contain a hashtable.
Parse error in script definition: {0} at line {1} column {2}.
@@ -217,21 +217,30 @@
Analyzing Script Definition.
- ConfigurationFileHasNoHashTable
+ SettingsFileHasNoHashTable
- ConfigurationFileNotFound
+ SettingsFileNotFound
- ConfigurationKeyNotAString
+ SettingsKeyNotAString
- ConfigurationValueNotAString
+ SettingsValueNotAString
- ConfigurationValueWrongFormat
+ SettingsValueWrongFormat
- WrongConfigurationKey
+ WrongSettingsKey
+
+
+ Key {0} in the settings is not a string.
+
+
+ {0} is not a valid key in the settings hashtable. Valid keys are ExcludeRules, IncludeRules and Severity.
+
+
+ Value {0} for key {1} has the wrong data type. Value in the settings hashtable should be a string or an array of strings.
\ No newline at end of file
diff --git a/Tests/Engine/GlobalSuppression.test.ps1 b/Tests/Engine/GlobalSuppression.test.ps1
index 9608071ed..285663ec4 100644
--- a/Tests/Engine/GlobalSuppression.test.ps1
+++ b/Tests/Engine/GlobalSuppression.test.ps1
@@ -14,19 +14,29 @@ $suppressionUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get
Describe "GlobalSuppression" {
Context "Exclude Rule" {
- It "Raises 1 violation for uninitialized variable and 1 for cmdlet alias" {
- $withoutProfile = $violations | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" -or $_.RuleName -eq "PSAvoidUninitializedVariable" }
+ It "Raises 1 violation for cmdlet alias" {
+ $withoutProfile = $violations | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases"}
$withoutProfile.Count | Should Be 1
- $withoutProfile = $violationsUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" -or $_.RuleName -eq "PSAvoidUninitializedVariable" }
+ $withoutProfile = $violationsUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases"}
$withoutProfile.Count | Should Be 1
}
- It "Does not raise any violations for uninitialized variable and cmdlet alias with profile" {
- $withProfile = $suppression | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" -or $_.RuleName -eq "PSAvoidUninitializedVariable" }
+ It "Does not raise any violations for cmdlet alias with profile" {
+ $withProfile = $suppression | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" }
$withProfile.Count | Should be 0
- $withProfile = $suppressionUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" -or $_.RuleName -eq "PSAvoidUninitializedVariable" }
+ $withProfile = $suppressionUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases" }
$withProfile.Count | Should be 0
}
+
+ It "Does not raise any violation for cmdlet alias using configuration hashtable" {
+ $hashtableConfiguration = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Configuration @{"excluderules" = "PSAvoidUsingCmdletAliases"} |
+ Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases"}
+ $hashtableConfiguration.Count | Should Be 0
+
+ $hashtableConfiguration = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$directory\GlobalSuppression.ps1") -Configuration @{"excluderules" = "PSAvoidUsingCmdletAliases"} |
+ Where-Object { $_.RuleName -eq "PSAvoidUsingCmdletAliases"}
+ $hashtableConfiguration.Count | Should Be 0
+ }
}
Context "Include Rule" {
@@ -43,6 +53,12 @@ Describe "GlobalSuppression" {
$withProfile = $suppressionUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSAvoidUsingComputerNameHardcoded" }
$withProfile.Count | Should be 0
}
+
+ It "Does not raise any violation for computername hard-coded using configuration hashtable" {
+ $hashtableConfiguration = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Settings @{"includerules" = @("PSAvoidUsingCmdletAliases", "PSUseOutputTypeCorrectly")} |
+ Where-Object { $_.RuleName -eq "PSAvoidUsingComputerNameHardcoded"}
+ $hashtableConfiguration.Count | Should Be 0
+ }
}
Context "Severity" {
@@ -59,25 +75,31 @@ Describe "GlobalSuppression" {
$withProfile = $suppressionUsingScriptDefinition | Where-Object { $_.RuleName -eq "PSUseOutputTypeCorrectly" }
$withProfile.Count | Should be 0
}
+
+ It "Does not raise any violation for use output type correctly with configuration hashtable" {
+ $hashtableConfiguration = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Settings @{"severity" = "warning"} |
+ Where-Object {$_.RuleName -eq "PSUseOutputTypeCorrectly"}
+ $hashtableConfiguration.Count | should be 0
+ }
}
Context "Error Case" {
It "Raises Error for file not found" {
- $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Configuration ".\ThisFileDoesNotExist.ps1" -ErrorAction SilentlyContinue
+ $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Settings ".\ThisFileDoesNotExist.ps1" -ErrorAction SilentlyContinue
$invokeWithError.Count | should be 0
- $Error[0].FullyQualifiedErrorId | should match "ConfigurationFileNotFound,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
+ $Error[0].FullyQualifiedErrorId | should match "SettingsFileNotFound,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
}
It "Raises Error for file with no hash table" {
- $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Configuration "$directory\GlobalSuppression.ps1" -ErrorAction SilentlyContinue
+ $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Settings "$directory\GlobalSuppression.ps1" -ErrorAction SilentlyContinue
$invokeWithError.Count | should be 0
- $Error[0].FullyQualifiedErrorId | should match "ConfigurationFileHasNoHashTable,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
+ $Error[0].FullyQualifiedErrorId | should match "SettingsFileHasNoHashTable,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
}
It "Raises Error for wrong profile" {
- $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Configuration "$directory\WrongProfile.ps1" -ErrorAction SilentlyContinue
+ $invokeWithError = Invoke-ScriptAnalyzer "$directory\GlobalSuppression.ps1" -Settings "$directory\WrongProfile.ps1" -ErrorAction SilentlyContinue
$invokeWithError.Count | should be 0
- $Error[0].FullyQualifiedErrorId | should match "WrongConfigurationKey,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
+ $Error[0].FullyQualifiedErrorId | should match "WrongSettingsKey,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
}
}
}
\ No newline at end of file
diff --git a/Tests/Engine/LibraryUsage.tests.ps1 b/Tests/Engine/LibraryUsage.tests.ps1
index 432ac8cee..1ae8eae60 100644
--- a/Tests/Engine/LibraryUsage.tests.ps1
+++ b/Tests/Engine/LibraryUsage.tests.ps1
@@ -39,16 +39,19 @@ function Invoke-ScriptAnalyzer {
[switch] $IncludeDefaultRules,
[Parameter(Mandatory = $false)]
- [switch] $SuppressedOnly,
-
- [Parameter(Mandatory = $false)]
- [string] $Profile = $null
+ [switch] $SuppressedOnly
)
if ($null -eq $CustomRulePath)
{
$IncludeDefaultRules = $true
}
+ # There is an inconsistency between this implementation and c# implementation of the cmdlet.
+ # The CustomRulePath parameter here is of "string[]" type whereas in the c# implementation it is of "string" type.
+ # If we set the CustomRulePath parameter here to "string[]", then the library usage test fails when run as an administrator.
+ # We want to note that the library usage test doesn't fail when run as a non-admin user.
+ # The following is the error statement when the test runs as an administrator.
+ # Assert failed on "Initialize" with "7" argument(s): "Test failed due to terminating error: The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)"
$scriptAnalyzer = New-Object "Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer";
$scriptAnalyzer.Initialize(
@@ -59,8 +62,7 @@ function Invoke-ScriptAnalyzer {
$ExcludeRule,
$Severity,
$IncludeDefaultRules.IsPresent,
- $SuppressedOnly.IsPresent,
- $Profile
+ $SuppressedOnly.IsPresent
);
if ($PSCmdlet.ParameterSetName -eq "File") {