@@ -112,6 +112,18 @@ public SwitchParameter Recurse
112112 }
113113 private bool recurse ;
114114
115+ /// <summary>
116+ /// ShowSuppressed: Show the suppressed message
117+ /// </summary>
118+ [ Parameter ( Mandatory = false ) ]
119+ [ SuppressMessage ( "Microsoft.Performance" , "CA1819:PropertiesShouldNotReturnArrays" ) ]
120+ public SwitchParameter SuppressedOnly
121+ {
122+ get { return suppressedOnly ; }
123+ set { suppressedOnly = value ; }
124+ }
125+ private bool suppressedOnly ;
126+
115127 #endregion Parameters
116128
117129 #region Private Members
@@ -183,7 +195,6 @@ protected override void BeginProcessing()
183195 #region Verify rules
184196
185197 rules = ScriptAnalyzer . Instance . ScriptRules . Union < IRule > (
186- ScriptAnalyzer . Instance . CommandRules ) . Union < IRule > (
187198 ScriptAnalyzer . Instance . TokenRules ) . Union < IRule > (
188199 ScriptAnalyzer . Instance . ExternalRules ?? Enumerable . Empty < IExternalRule > ( ) ) ;
189200
@@ -270,7 +281,7 @@ private void AnalyzeFile(string filePath)
270281 Token [ ] tokens = null ;
271282 ParseError [ ] errors = null ;
272283 List < DiagnosticRecord > diagnostics = new List < DiagnosticRecord > ( ) ;
273- IEnumerable < Ast > funcDefAsts ;
284+ List < SuppressedRecord > suppressed = new List < SuppressedRecord > ( ) ;
274285
275286 // Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash
276287 List < KeyValuePair < CommandInfo , IScriptExtent > > cmdInfoTable = new List < KeyValuePair < CommandInfo , IScriptExtent > > ( ) ;
@@ -325,6 +336,19 @@ private void AnalyzeFile(string filePath)
325336 return ;
326337 }
327338
339+ Dictionary < string , List < RuleSuppression > > ruleSuppressions = Helper . Instance . GetRuleSuppression ( ast ) ;
340+
341+ foreach ( List < RuleSuppression > ruleSuppressionsList in ruleSuppressions . Values )
342+ {
343+ foreach ( RuleSuppression ruleSuppression in ruleSuppressionsList )
344+ {
345+ if ( ! String . IsNullOrWhiteSpace ( ruleSuppression . Error ) )
346+ {
347+ WriteError ( new ErrorRecord ( new ArgumentException ( ruleSuppression . Error ) , ruleSuppression . Error , ErrorCategory . InvalidArgument , ruleSuppression ) ) ;
348+ }
349+ }
350+ }
351+
328352 #region Run VariableAnalysis
329353 try
330354 {
@@ -353,6 +377,7 @@ private void AnalyzeFile(string filePath)
353377 break ;
354378 }
355379 }
380+
356381 foreach ( Regex exclude in excludeRegexList )
357382 {
358383 if ( exclude . IsMatch ( scriptRule . GetName ( ) ) )
@@ -361,97 +386,22 @@ private void AnalyzeFile(string filePath)
361386 break ;
362387 }
363388 }
364- if ( ( includeRule == null || includeRegexMatch ) && ( excludeRule == null || ! excludeRegexMatch ) )
389+
390+ if ( ( includeRule == null || includeRegexMatch ) && ( excludeRule == null || ! excludeRegexMatch ) )
365391 {
366392 WriteVerbose ( string . Format ( CultureInfo . CurrentCulture , Strings . VerboseRunningMessage , scriptRule . GetName ( ) ) ) ;
367393
368394 // Ensure that any unhandled errors from Rules are converted to non-terminating errors
369395 // We want the Engine to continue functioning even if one or more Rules throws an exception
370396 try
371397 {
372- diagnostics . AddRange ( scriptRule . AnalyzeScript ( ast , filePath ) ) ;
398+ var records = Helper . Instance . SuppressRule ( scriptRule . GetName ( ) , ruleSuppressions , scriptRule . AnalyzeScript ( ast , filePath ) . ToList ( ) ) ;
399+ diagnostics . AddRange ( records . Item2 ) ;
400+ suppressed . AddRange ( records . Item1 ) ;
373401 }
374402 catch ( Exception scriptRuleException )
375403 {
376- WriteError ( new ErrorRecord ( scriptRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , filePath ) ) ;
377- }
378- }
379- }
380- }
381-
382- #endregion
383-
384- #region Run Command Rules
385-
386- funcDefAsts = ast . FindAll ( new Func < Ast , bool > ( ( testAst ) => ( testAst is FunctionDefinitionAst ) ) , true ) ;
387- if ( funcDefAsts != null )
388- {
389- foreach ( FunctionDefinitionAst funcDefAst in funcDefAsts )
390- {
391- //Create command info object here
392- var sb = new StringBuilder ( ) ;
393- sb . AppendLine ( funcDefAst . Extent . Text ) ;
394- sb . AppendFormat ( "Get-Command –CommandType Function –Name {0}" , funcDefAst . Name ) ;
395-
396- var funcDefPS = System . Management . Automation . PowerShell . Create ( RunspaceMode . CurrentRunspace ) ;
397- funcDefPS . AddScript ( sb . ToString ( ) ) ;
398-
399- try
400- {
401- var commandInfo = funcDefPS . Invoke < CommandInfo > ( ) ;
402-
403- foreach ( CommandInfo cmdInfo in commandInfo )
404- {
405- cmdInfoTable . Add ( new KeyValuePair < CommandInfo , IScriptExtent > ( cmdInfo as CommandInfo , funcDefAst . Extent ) ) ;
406- }
407- }
408- catch ( ParseException )
409- {
410- WriteError ( new ErrorRecord ( new CommandNotFoundException ( ) ,
411- string . Format ( CultureInfo . CurrentCulture , Strings . CommandInfoNotFound , funcDefAst . Name ) ,
412- ErrorCategory . SyntaxError , funcDefAst ) ) ;
413- }
414- }
415- }
416-
417- if ( ScriptAnalyzer . Instance . CommandRules != null )
418- {
419- foreach ( ICommandRule commandRule in ScriptAnalyzer . Instance . CommandRules )
420- {
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 ) )
440- {
441- foreach ( KeyValuePair < CommandInfo , IScriptExtent > commandInfo in cmdInfoTable )
442- {
443- WriteVerbose ( string . Format ( CultureInfo . CurrentCulture , Strings . VerboseRunningMessage , commandRule . GetName ( ) ) ) ;
444-
445- // Ensure that any unhandled errors from Rules are converted to non-terminating errors
446- // We want the Engine to continue functioning even if one or more Rules throws an exception
447- try
448- {
449- diagnostics . AddRange ( commandRule . AnalyzeCommand ( commandInfo . Key , commandInfo . Value , fileName ) ) ;
450- }
451- catch ( Exception commandRuleException )
452- {
453- WriteError ( new ErrorRecord ( commandRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , fileName ) ) ;
454- }
404+ WriteError ( new ErrorRecord ( scriptRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , filePath ) ) ;
455405 }
456406 }
457407 }
@@ -491,11 +441,13 @@ private void AnalyzeFile(string filePath)
491441 // We want the Engine to continue functioning even if one or more Rules throws an exception
492442 try
493443 {
494- diagnostics . AddRange ( tokenRule . AnalyzeTokens ( tokens , fileName ) ) ;
444+ var records = Helper . Instance . SuppressRule ( tokenRule . GetName ( ) , ruleSuppressions , tokenRule . AnalyzeTokens ( tokens , filePath ) . ToList ( ) ) ;
445+ diagnostics . AddRange ( records . Item2 ) ;
446+ suppressed . AddRange ( records . Item1 ) ;
495447 }
496448 catch ( Exception tokenRuleException )
497449 {
498- WriteError ( new ErrorRecord ( tokenRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , fileName ) ) ;
450+ WriteError ( new ErrorRecord ( tokenRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , fileName ) ) ;
499451 }
500452 }
501453 }
@@ -511,6 +463,7 @@ private void AnalyzeFile(string filePath)
511463 {
512464 bool includeRegexMatch = false ;
513465 bool excludeRegexMatch = false ;
466+
514467 foreach ( Regex include in includeRegexList )
515468 {
516469 if ( include . IsMatch ( dscResourceRule . GetName ( ) ) )
@@ -519,6 +472,7 @@ private void AnalyzeFile(string filePath)
519472 break ;
520473 }
521474 }
475+
522476 foreach ( Regex exclude in excludeRegexList )
523477 {
524478 if ( exclude . IsMatch ( dscResourceRule . GetName ( ) ) )
@@ -527,6 +481,7 @@ private void AnalyzeFile(string filePath)
527481 break ;
528482 }
529483 }
484+
530485 if ( ( includeRule == null || includeRegexMatch ) && ( excludeRule == null || excludeRegexMatch ) )
531486 {
532487 WriteVerbose ( string . Format ( CultureInfo . CurrentCulture , Strings . VerboseRunningMessage , dscResourceRule . GetName ( ) ) ) ;
@@ -535,11 +490,13 @@ private void AnalyzeFile(string filePath)
535490 // We want the Engine to continue functioning even if one or more Rules throws an exception
536491 try
537492 {
538- diagnostics . AddRange ( dscResourceRule . AnalyzeDSCClass ( ast , filePath ) ) ;
493+ var records = Helper . Instance . SuppressRule ( dscResourceRule . GetName ( ) , ruleSuppressions , dscResourceRule . AnalyzeDSCClass ( ast , filePath ) . ToList ( ) ) ;
494+ diagnostics . AddRange ( records . Item2 ) ;
495+ suppressed . AddRange ( records . Item1 ) ;
539496 }
540497 catch ( Exception dscResourceRuleException )
541498 {
542- WriteError ( new ErrorRecord ( dscResourceRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , filePath ) ) ;
499+ WriteError ( new ErrorRecord ( dscResourceRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , filePath ) ) ;
543500 }
544501 }
545502 }
@@ -592,11 +549,13 @@ private void AnalyzeFile(string filePath)
592549 // We want the Engine to continue functioning even if one or more Rules throws an exception
593550 try
594551 {
595- diagnostics . AddRange ( dscResourceRule . AnalyzeDSCResource ( ast , filePath ) ) ;
552+ var records = Helper . Instance . SuppressRule ( dscResourceRule . GetName ( ) , ruleSuppressions , dscResourceRule . AnalyzeDSCResource ( ast , filePath ) . ToList ( ) ) ;
553+ diagnostics . AddRange ( records . Item2 ) ;
554+ suppressed . AddRange ( records . Item1 ) ;
596555 }
597556 catch ( Exception dscResourceRuleException )
598557 {
599- WriteError ( new ErrorRecord ( dscResourceRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , filePath ) ) ;
558+ WriteError ( new ErrorRecord ( dscResourceRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , filePath ) ) ;
600559 }
601560 }
602561 }
@@ -630,7 +589,7 @@ private void AnalyzeFile(string filePath)
630589 }
631590 catch ( Exception externalRuleException )
632591 {
633- WriteError ( new ErrorRecord ( externalRuleException , Strings . RuleError , ErrorCategory . InvalidOperation , fileName ) ) ;
592+ WriteError ( new ErrorRecord ( externalRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , fileName ) ) ;
634593 }
635594 }
636595 }
@@ -649,9 +608,19 @@ private void AnalyzeFile(string filePath)
649608 //Output through loggers
650609 foreach ( ILogger logger in ScriptAnalyzer . Instance . Loggers )
651610 {
652- foreach ( DiagnosticRecord diagnostic in diagnostics )
611+ if ( SuppressedOnly )
653612 {
654- logger . LogMessage ( diagnostic , this ) ;
613+ foreach ( DiagnosticRecord suppressRecord in suppressed )
614+ {
615+ logger . LogObject ( suppressRecord , this ) ;
616+ }
617+ }
618+ else
619+ {
620+ foreach ( DiagnosticRecord diagnostic in diagnostics )
621+ {
622+ logger . LogObject ( diagnostic , this ) ;
623+ }
655624 }
656625 }
657626 }
0 commit comments