Skip to content

Commit 7492146

Browse files
committed
Merge pull request #64 from PowerShell/BugFixes
Merge BugFixes to Master
2 parents 4cd6e49 + ad6350d commit 7492146

File tree

66 files changed

+883
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+883
-307
lines changed

Engine/Commands/GetScriptAnalyzerRuleCommand.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,14 @@
1010
// THE SOFTWARE.
1111
//
1212

13+
using Microsoft.PowerShell.Commands;
1314
using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic;
1415
using System;
1516
using System.Collections.Generic;
16-
using System.ComponentModel.Composition;
1717
using System.Diagnostics.CodeAnalysis;
1818
using System.Globalization;
1919
using System.Linq;
2020
using System.Management.Automation;
21-
using System.Resources;
22-
using System.Threading;
23-
using System.Reflection;
2421

2522
namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Commands
2623
{
@@ -50,12 +47,27 @@ public string[] CustomizedRulePath
5047
[Parameter(Mandatory = false)]
5148
[ValidateNotNullOrEmpty]
5249
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
53-
public string[] Name
50+
public string[] RuleName
5451
{
5552
get { return name; }
5653
set { name = value; }
5754
}
5855
private string[] name;
56+
57+
/// <summary>
58+
/// Severity: Array of the severity types to be enabled.
59+
/// </summary>
60+
/// </summary>
61+
[ValidateSet("Warning", "Error", "Information", IgnoreCase = true)]
62+
[Parameter(Mandatory = false)]
63+
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
64+
public string[] Severity
65+
{
66+
get { return severity; }
67+
set { severity = value; }
68+
}
69+
private string[] severity;
70+
5971
#endregion Parameters
6072

6173
#region Private Members
@@ -128,9 +140,16 @@ protected override void ProcessRecord()
128140
}
129141
else
130142
{
143+
if (severity != null)
144+
{
145+
var ruleSeverity = severity.Select(item => Enum.Parse(typeof (RuleSeverity), item));
146+
rules = rules.Where(item => ruleSeverity.Contains(item.GetSeverity())).ToList();
147+
}
148+
131149
foreach (IRule rule in rules)
132150
{
133-
WriteObject(new RuleInfo(rule.GetName(), rule.GetCommonName(), rule.GetDescription(), rule.GetSourceType(), rule.GetSourceName()));
151+
WriteObject(new RuleInfo(rule.GetName(), rule.GetCommonName(), rule.GetDescription(),
152+
rule.GetSourceType(), rule.GetSourceName(), rule.GetSeverity()));
134153
}
135154
}
136155
}

Engine/Commands/InvokeScriptAnalyzerCommand.cs

Lines changed: 118 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// THE SOFTWARE.
1111
//
1212

13+
using System.Text.RegularExpressions;
1314
using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic;
1415
using System;
1516
using System.Collections.Generic;
@@ -272,7 +273,28 @@ private void AnalyzeFile(string filePath)
272273
IEnumerable<Ast> funcDefAsts;
273274

274275
// Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash
275-
List<KeyValuePair<CommandInfo, IScriptExtent>> cmdInfoTable = new List<KeyValuePair<CommandInfo, IScriptExtent>>();
276+
List<KeyValuePair<CommandInfo, IScriptExtent>> cmdInfoTable = new List<KeyValuePair<CommandInfo, IScriptExtent>>();
277+
278+
//Check wild card input for the Include/ExcludeRules and create regex match patterns
279+
List<Regex> includeRegexList = new List<Regex>();
280+
List<Regex> excludeRegexList = new List<Regex>();
281+
if (includeRule != null)
282+
{
283+
foreach (string rule in includeRule)
284+
{
285+
Regex includeRegex = new Regex(String.Format("^{0}$", Regex.Escape(rule).Replace(@"\*", ".*")), RegexOptions.IgnoreCase);
286+
includeRegexList.Add(includeRegex);
287+
}
288+
}
289+
if (excludeRule != null)
290+
{
291+
foreach (string rule in excludeRule)
292+
{
293+
Regex excludeRegex = new Regex(String.Format("^{0}$", Regex.Escape(rule).Replace(@"\*", ".*")), RegexOptions.IgnoreCase);
294+
excludeRegexList.Add(excludeRegex);
295+
}
296+
}
297+
276298

277299
//Parse the file
278300
if (File.Exists(filePath))
@@ -316,12 +338,30 @@ private void AnalyzeFile(string filePath)
316338
#region Run ScriptRules
317339
//Trim down to the leaf element of the filePath and pass it to Diagnostic Record
318340
string fileName = System.IO.Path.GetFileName(filePath);
341+
319342
if (ScriptAnalyzer.Instance.ScriptRules != null)
320343
{
321344
foreach (IScriptRule scriptRule in ScriptAnalyzer.Instance.ScriptRules)
322345
{
323-
if ((includeRule == null || includeRule.Contains(scriptRule.GetName(), StringComparer.OrdinalIgnoreCase)) &&
324-
(excludeRule == null || !excludeRule.Contains(scriptRule.GetName(), StringComparer.OrdinalIgnoreCase)))
346+
bool includeRegexMatch = false;
347+
bool excludeRegexMatch = false;
348+
foreach (Regex include in includeRegexList)
349+
{
350+
if (include.IsMatch(scriptRule.GetName()))
351+
{
352+
includeRegexMatch = true;
353+
break;
354+
}
355+
}
356+
foreach (Regex exclude in excludeRegexList)
357+
{
358+
if (exclude.IsMatch(scriptRule.GetName()))
359+
{
360+
excludeRegexMatch = true;
361+
break;
362+
}
363+
}
364+
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
325365
{
326366
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, scriptRule.GetName()));
327367

@@ -334,7 +374,6 @@ private void AnalyzeFile(string filePath)
334374
catch (Exception scriptRuleException)
335375
{
336376
WriteError(new ErrorRecord(scriptRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
337-
continue;
338377
}
339378
}
340379
}
@@ -379,8 +418,25 @@ private void AnalyzeFile(string filePath)
379418
{
380419
foreach (ICommandRule commandRule in ScriptAnalyzer.Instance.CommandRules)
381420
{
382-
if ((includeRule == null || includeRule.Contains(commandRule.GetName(), StringComparer.OrdinalIgnoreCase)) &&
383-
(excludeRule == null || !excludeRule.Contains(commandRule.GetName(), StringComparer.OrdinalIgnoreCase)))
421+
bool includeRegexMatch = false;
422+
bool excludeRegexMatch = false;
423+
foreach (Regex include in includeRegexList)
424+
{
425+
if (include.IsMatch(commandRule.GetName()))
426+
{
427+
includeRegexMatch = true;
428+
break;
429+
}
430+
}
431+
foreach (Regex exclude in excludeRegexList)
432+
{
433+
if (exclude.IsMatch(commandRule.GetName()))
434+
{
435+
excludeRegexMatch = true;
436+
break;
437+
}
438+
}
439+
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
384440
{
385441
foreach (KeyValuePair<CommandInfo, IScriptExtent> commandInfo in cmdInfoTable)
386442
{
@@ -395,7 +451,6 @@ private void AnalyzeFile(string filePath)
395451
catch (Exception commandRuleException)
396452
{
397453
WriteError(new ErrorRecord(commandRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
398-
continue;
399454
}
400455
}
401456
}
@@ -410,8 +465,25 @@ private void AnalyzeFile(string filePath)
410465
{
411466
foreach (ITokenRule tokenRule in ScriptAnalyzer.Instance.TokenRules)
412467
{
413-
if ((includeRule == null || includeRule.Contains(tokenRule.GetName(), StringComparer.OrdinalIgnoreCase)) &&
414-
(excludeRule == null || !excludeRule.Contains(tokenRule.GetName(), StringComparer.OrdinalIgnoreCase)))
468+
bool includeRegexMatch = false;
469+
bool excludeRegexMatch = false;
470+
foreach (Regex include in includeRegexList)
471+
{
472+
if (include.IsMatch(tokenRule.GetName()))
473+
{
474+
includeRegexMatch = true;
475+
break;
476+
}
477+
}
478+
foreach (Regex exclude in excludeRegexList)
479+
{
480+
if (exclude.IsMatch(tokenRule.GetName()))
481+
{
482+
excludeRegexMatch = true;
483+
break;
484+
}
485+
}
486+
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
415487
{
416488
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, tokenRule.GetName()));
417489

@@ -424,7 +496,6 @@ private void AnalyzeFile(string filePath)
424496
catch (Exception tokenRuleException)
425497
{
426498
WriteError(new ErrorRecord(tokenRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName));
427-
continue;
428499
}
429500
}
430501
}
@@ -438,8 +509,25 @@ private void AnalyzeFile(string filePath)
438509
// Run DSC Class rule
439510
foreach (IDSCResourceRule dscResourceRule in ScriptAnalyzer.Instance.DSCResourceRules)
440511
{
441-
if ((includeRule == null || includeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)) &&
442-
(excludeRule == null || !excludeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)))
512+
bool includeRegexMatch = false;
513+
bool excludeRegexMatch = false;
514+
foreach (Regex include in includeRegexList)
515+
{
516+
if (include.IsMatch(dscResourceRule.GetName()))
517+
{
518+
includeRegexMatch = true;
519+
break;
520+
}
521+
}
522+
foreach (Regex exclude in excludeRegexList)
523+
{
524+
if (exclude.IsMatch(dscResourceRule.GetName()))
525+
{
526+
excludeRegexMatch = true;
527+
break;
528+
}
529+
}
530+
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || excludeRegexMatch))
443531
{
444532
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, dscResourceRule.GetName()));
445533

@@ -452,7 +540,6 @@ private void AnalyzeFile(string filePath)
452540
catch (Exception dscResourceRuleException)
453541
{
454542
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
455-
continue;
456543
}
457544
}
458545
}
@@ -480,8 +567,24 @@ private void AnalyzeFile(string filePath)
480567
// Run all DSC Rules
481568
foreach (IDSCResourceRule dscResourceRule in ScriptAnalyzer.Instance.DSCResourceRules)
482569
{
483-
if ((includeRule == null || includeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)) &&
484-
(excludeRule == null || !excludeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)))
570+
bool includeRegexMatch = false;
571+
bool excludeRegexMatch = false;
572+
foreach (Regex include in includeRegexList)
573+
{
574+
if (include.IsMatch(dscResourceRule.GetName()))
575+
{
576+
includeRegexMatch = true;
577+
break;
578+
}
579+
}
580+
foreach (Regex exclude in excludeRegexList)
581+
{
582+
if (exclude.IsMatch(dscResourceRule.GetName()))
583+
{
584+
excludeRegexMatch = true;
585+
}
586+
}
587+
if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch))
485588
{
486589
WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, dscResourceRule.GetName()));
487590

@@ -494,7 +597,6 @@ private void AnalyzeFile(string filePath)
494597
catch (Exception dscResourceRuleException)
495598
{
496599
WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath));
497-
continue;
498600
}
499601
}
500602
}

Engine/Generic/AvoidCmdletGeneric.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,11 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
9393
/// </summary>
9494
/// <returns>The source type of the rule.</returns>
9595
public abstract SourceType GetSourceType();
96+
97+
/// <summary>
98+
/// GetSeverity: Retrieves the severity of the rule: error, warning of information.
99+
/// </summary>
100+
/// <returns></returns>
101+
public abstract RuleSeverity GetSeverity();
96102
}
97103
}

Engine/Generic/AvoidParameterGeneric.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
104104
/// </summary>
105105
/// <returns>The source type of the rule.</returns>
106106
public abstract SourceType GetSourceType();
107+
108+
public abstract RuleSeverity GetSeverity();
107109
}
108110
}

Engine/Generic/ExternalRule.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ public SourceType GetSourceType()
5555
return SourceType.Module;
5656
}
5757

58+
//Set the community rule level as warning as the current implementation does not require user to specify rule severity when defining their functions in PS scripts
59+
public RuleSeverity GetSeverity()
60+
{
61+
return RuleSeverity.Warning;
62+
}
63+
5864
public string GetSourceName()
5965
{
6066
return this.srcName;

Engine/Generic/IRule.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@
1010
// THE SOFTWARE.
1111
//
1212

13-
using System;
14-
using System.Collections.Generic;
15-
using System.Linq;
16-
using System.Text;
17-
using System.Threading.Tasks;
18-
1913
namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Generic
2014
{
2115
/// <summary>
@@ -52,5 +46,12 @@ public interface IRule
5246
/// </summary>
5347
/// <returns>The source type of the rule.</returns>
5448
SourceType GetSourceType();
49+
50+
/// <summary>
51+
/// GetSeverity: Retrieves severity of the rule.
52+
/// </summary>
53+
/// <returns></returns>
54+
RuleSeverity GetSeverity();
55+
5556
}
5657
}

Engine/Generic/RuleInfo.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ public class RuleInfo
2929
private string description;
3030
private SourceType sourceType;
3131
private string sourceName;
32+
private RuleSeverity ruleSeverity;
3233

3334
/// <summary>
3435
/// Name: The name of the rule.
3536
/// </summary>
3637
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
37-
public string Name
38+
public string RuleName
3839
{
3940
get { return name; }
4041
private set { name = value; }
@@ -81,6 +82,16 @@ public string SourceName
8182
private set { sourceName = value; }
8283
}
8384

85+
/// <summary>
86+
/// Severity : The severity of the rule violation.
87+
/// </summary>
88+
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
89+
public RuleSeverity Severity
90+
{
91+
get { return ruleSeverity; }
92+
private set { ruleSeverity = value; }
93+
}
94+
8495
/// <summary>
8596
/// Constructor for a RuleInfo.
8697
/// </summary>
@@ -89,13 +100,14 @@ public string SourceName
89100
/// <param name="description">Description of the rule.</param>
90101
/// <param name="sourceType">Source type of the rule.</param>
91102
/// <param name="sourceName">Source name of the rule.</param>
92-
public RuleInfo(string name, string commonName, string description, SourceType sourceType, string sourceName)
103+
public RuleInfo(string name, string commonName, string description, SourceType sourceType, string sourceName, RuleSeverity severity)
93104
{
94-
Name = name;
105+
RuleName = name;
95106
CommonName = commonName;
96107
Description = description;
97108
SourceType = sourceType;
98109
SourceName = sourceName;
110+
Severity = severity;
99111
}
100112
}
101113
}

0 commit comments

Comments
 (0)