Skip to content

Commit 2b5c26a

Browse files
author
Kapil Borle
committed
Fix invoking WriteError from rule execution threads
Whenever Helper.SuppressRule encounters any error, it invokes Cmdlet.WriteError. When running script rules, SuppressRule is called from rule execution threads. As such, Cmdlet.WriteError gets called from the rule execution threads. This results in an InvalidOperationException because this method can be called only from within BeginProcessing, ProcessRecord and EndProcessing and only within the main program thread.
1 parent e919621 commit 2b5c26a

2 files changed

Lines changed: 55 additions & 21 deletions

File tree

Engine/Helper.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,12 +1190,16 @@ internal List<RuleSuppression> GetSuppressionsClass(TypeDefinitionAst typeAst)
11901190
/// </summary>
11911191
/// <param name="ruleSuppressions"></param>
11921192
/// <param name="diagnostics"></param>
1193-
public Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> SuppressRule(string ruleName, Dictionary<string, List<RuleSuppression>> ruleSuppressionsDict, List<DiagnosticRecord> diagnostics)
1193+
public Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> SuppressRule(
1194+
string ruleName,
1195+
Dictionary<string, List<RuleSuppression>> ruleSuppressionsDict,
1196+
List<DiagnosticRecord> diagnostics,
1197+
out List<ErrorRecord> errorRecords)
11941198
{
11951199
List<SuppressedRecord> suppressedRecords = new List<SuppressedRecord>();
11961200
List<DiagnosticRecord> unSuppressedRecords = new List<DiagnosticRecord>();
11971201
Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> result = Tuple.Create(suppressedRecords, unSuppressedRecords);
1198-
1202+
errorRecords = new List<ErrorRecord>();
11991203
if (diagnostics == null || diagnostics.Count == 0)
12001204
{
12011205
return result;
@@ -1261,8 +1265,8 @@ public Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> SuppressRule(string
12611265
ruleSuppression.Error = String.Format(CultureInfo.CurrentCulture, Strings.RuleSuppressionErrorFormat, ruleSuppression.StartAttributeLine,
12621266
System.IO.Path.GetFileName(diagnostics.First().Extent.File), String.Format(Strings.RuleSuppressionIDError, ruleSuppression.RuleSuppressionID));
12631267
}
1264-
1265-
this.outputWriter.WriteError(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
1268+
errorRecords.Add(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
1269+
//this.outputWriter.WriteError(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
12661270
}
12671271
}
12681272

Engine/ScriptAnalyzer.cs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,31 @@ bool IsRuleAllowed(IRule rule)
13851385
&& IsSeverityAllowed(allowedSeverities, rule);
13861386
}
13871387

1388+
/// <summary>
1389+
/// Wrapper around the Helper.SuppressRule method
1390+
/// </summary>
1391+
/// <param name="ruleName"></param>
1392+
/// <param name="ruleSuppressions"></param>
1393+
/// <param name="ruleDiagnosticRecords"></param>
1394+
/// <returns>Returns a tuple of suppressed and diagnostic records</returns>
1395+
private Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> SuppressRule(
1396+
string ruleName,
1397+
Dictionary<string, List<RuleSuppression>> ruleSuppressions,
1398+
List<DiagnosticRecord> ruleDiagnosticRecords)
1399+
{
1400+
List<ErrorRecord> suppressRuleErrors;
1401+
var records = Helper.Instance.SuppressRule(
1402+
ruleName,
1403+
ruleSuppressions,
1404+
ruleDiagnosticRecords,
1405+
out suppressRuleErrors);
1406+
foreach (var error in suppressRuleErrors)
1407+
{
1408+
this.outputWriter.WriteError(error);
1409+
}
1410+
return records;
1411+
}
1412+
13881413
/// <summary>
13891414
/// Analyzes the syntax tree of a script file that has already been parsed.
13901415
/// </summary>
@@ -1445,7 +1470,6 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
14451470
if (this.ScriptRules != null)
14461471
{
14471472
var allowedRules = this.ScriptRules.Where(IsRuleAllowed);
1448-
14491473
if (allowedRules.Any())
14501474
{
14511475
var tasks = allowedRules.Select(scriptRule => Task.Factory.StartNew(() =>
@@ -1468,7 +1492,14 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
14681492
}
14691493
else if (!helpRule && !helpFile)
14701494
{
1471-
var records = Helper.Instance.SuppressRule(scriptRule.GetName(), ruleSuppressions, scriptRule.AnalyzeScript(scriptAst, scriptAst.Extent.File).ToList());
1495+
List<ErrorRecord> suppressRuleErrors;
1496+
var ruleRecords = scriptRule.AnalyzeScript(scriptAst, scriptAst.Extent.File).ToList();
1497+
var records = Helper.Instance.SuppressRule(
1498+
scriptRule.GetName(),
1499+
ruleSuppressions,
1500+
ruleRecords,
1501+
out suppressRuleErrors);
1502+
result.AddRange(suppressRuleErrors);
14721503
foreach (var record in records.Item2)
14731504
{
14741505
diagnostics.Add(record);
@@ -1486,9 +1517,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
14861517

14871518
verboseOrErrors.Add(result);
14881519
}));
1489-
14901520
Task.Factory.ContinueWhenAll(tasks.ToArray(), t => verboseOrErrors.CompleteAdding());
1491-
14921521
while (!verboseOrErrors.IsCompleted)
14931522
{
14941523
List<object> data = null;
@@ -1501,9 +1530,12 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
15011530
if (data != null)
15021531
{
15031532
this.outputWriter.WriteVerbose(data[0] as string);
1504-
if (data.Count == 2)
1533+
if (data.Count > 1)
15051534
{
1506-
this.outputWriter.WriteError(data[1] as ErrorRecord);
1535+
for (int count = 1; count < data.Count; count++)
1536+
{
1537+
this.outputWriter.WriteError(data[count] as ErrorRecord);
1538+
}
15071539
}
15081540
}
15091541
}
@@ -1526,7 +1558,8 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
15261558
// We want the Engine to continue functioning even if one or more Rules throws an exception
15271559
try
15281560
{
1529-
var records = Helper.Instance.SuppressRule(tokenRule.GetName(), ruleSuppressions, tokenRule.AnalyzeTokens(scriptTokens, filePath).ToList());
1561+
var ruleRecords = tokenRule.AnalyzeTokens(scriptTokens, filePath).ToList();
1562+
var records = SuppressRule(tokenRule.GetName(), ruleSuppressions, ruleRecords);
15301563
foreach (var record in records.Item2)
15311564
{
15321565
diagnostics.Add(record);
@@ -1584,16 +1617,12 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
15841617
// We want the Engine to continue functioning even if one or more Rules throws an exception
15851618
try
15861619
{
1587-
#if PSV3
1588-
1620+
#if PSV3
15891621
var records = Helper.Instance.SuppressRule(dscResourceRule.GetName(), ruleSuppressions, null);
1590-
1591-
#else
1592-
1593-
var records = Helper.Instance.SuppressRule(dscResourceRule.GetName(), ruleSuppressions, dscResourceRule.AnalyzeDSCClass(scriptAst, filePath).ToList());
1594-
1595-
#endif
1596-
1622+
#else
1623+
var ruleRecords = dscResourceRule.AnalyzeDSCClass(scriptAst, filePath).ToList();
1624+
var records = SuppressRule(dscResourceRule.GetName(), ruleSuppressions, ruleRecords);
1625+
#endif
15971626
foreach (var record in records.Item2)
15981627
{
15991628
diagnostics.Add(record);
@@ -1625,7 +1654,8 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
16251654
// We want the Engine to continue functioning even if one or more Rules throws an exception
16261655
try
16271656
{
1628-
var records = Helper.Instance.SuppressRule(dscResourceRule.GetName(), ruleSuppressions, dscResourceRule.AnalyzeDSCResource(scriptAst, filePath).ToList());
1657+
var ruleRecords = dscResourceRule.AnalyzeDSCResource(scriptAst, filePath).ToList();
1658+
var records = SuppressRule(dscResourceRule.GetName(), ruleSuppressions, ruleRecords);
16291659
foreach (var record in records.Item2)
16301660
{
16311661
diagnostics.Add(record);

0 commit comments

Comments
 (0)