12
12
13
13
using System . Text . RegularExpressions ;
14
14
using System ;
15
+ using System . ComponentModel ;
15
16
using System . Collections . Generic ;
16
17
using System . Diagnostics . CodeAnalysis ;
17
18
using System . Globalization ;
20
21
using System . Management . Automation . Language ;
21
22
using System . IO ;
22
23
using Microsoft . Windows . PowerShell . ScriptAnalyzer . Generic ;
24
+ using System . Threading . Tasks ;
25
+ using System . Collections . Concurrent ;
26
+ using System . Threading ;
23
27
24
28
namespace Microsoft . Windows . PowerShell . ScriptAnalyzer . Commands
25
29
{
@@ -267,6 +271,14 @@ private void ProcessPath(string path)
267
271
268
272
}
269
273
274
+ ConcurrentBag < DiagnosticRecord > diagnostics ;
275
+ ConcurrentBag < SuppressedRecord > suppressed ;
276
+ Dictionary < string , List < RuleSuppression > > ruleSuppressions ;
277
+ List < Regex > includeRegexList ;
278
+ List < Regex > excludeRegexList ;
279
+ CountdownEvent cde ;
280
+ ConcurrentDictionary < string , List < object > > ruleDictionary ;
281
+
270
282
/// <summary>
271
283
/// Analyzes a single script file.
272
284
/// </summary>
@@ -275,15 +287,16 @@ private void AnalyzeFile(string filePath)
275
287
{
276
288
Token [ ] tokens = null ;
277
289
ParseError [ ] errors = null ;
278
- List < DiagnosticRecord > diagnostics = new List < DiagnosticRecord > ( ) ;
279
- List < SuppressedRecord > suppressed = new List < SuppressedRecord > ( ) ;
290
+ diagnostics = new ConcurrentBag < DiagnosticRecord > ( ) ;
291
+ suppressed = new ConcurrentBag < SuppressedRecord > ( ) ;
292
+ ruleDictionary = new ConcurrentDictionary < string , List < object > > ( ) ;
280
293
281
294
// Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash
282
295
List < KeyValuePair < CommandInfo , IScriptExtent > > cmdInfoTable = new List < KeyValuePair < CommandInfo , IScriptExtent > > ( ) ;
283
296
284
297
//Check wild card input for the Include/ExcludeRules and create regex match patterns
285
- List < Regex > includeRegexList = new List < Regex > ( ) ;
286
- List < Regex > excludeRegexList = new List < Regex > ( ) ;
298
+ includeRegexList = new List < Regex > ( ) ;
299
+ excludeRegexList = new List < Regex > ( ) ;
287
300
if ( includeRule != null )
288
301
{
289
302
foreach ( string rule in includeRule )
@@ -331,7 +344,7 @@ private void AnalyzeFile(string filePath)
331
344
return ;
332
345
}
333
346
334
- Dictionary < string , List < RuleSuppression > > ruleSuppressions = Helper . Instance . GetRuleSuppression ( ast ) ;
347
+ ruleSuppressions = Helper . Instance . GetRuleSuppression ( ast ) ;
335
348
336
349
foreach ( List < RuleSuppression > ruleSuppressionsList in ruleSuppressions . Values )
337
350
{
@@ -360,44 +373,24 @@ private void AnalyzeFile(string filePath)
360
373
361
374
if ( ScriptAnalyzer . Instance . ScriptRules != null )
362
375
{
363
- foreach ( IScriptRule scriptRule in ScriptAnalyzer . Instance . ScriptRules )
376
+ cde = new CountdownEvent ( ScriptAnalyzer . Instance . ScriptRules . Count ( ) ) ;
377
+
378
+ foreach ( var scriptRule in ScriptAnalyzer . Instance . ScriptRules )
364
379
{
365
- bool includeRegexMatch = false ;
366
- bool excludeRegexMatch = false ;
367
- foreach ( Regex include in includeRegexList )
368
- {
369
- if ( include . IsMatch ( scriptRule . GetName ( ) ) )
370
- {
371
- includeRegexMatch = true ;
372
- break ;
373
- }
374
- }
380
+ BackgroundWorker bg = new BackgroundWorker ( ) ;
381
+ bg . DoWork += bg_DoWork ;
382
+ bg . RunWorkerAsync ( new object [ ] { scriptRule } ) ;
383
+ }
375
384
376
- foreach ( Regex exclude in excludeRegexList )
377
- {
378
- if ( exclude . IsMatch ( scriptRule . GetName ( ) ) )
379
- {
380
- excludeRegexMatch = true ;
381
- break ;
382
- }
383
- }
385
+ cde . Wait ( ) ;
384
386
385
- if ( ( includeRule == null || includeRegexMatch ) && ( excludeRule == null || ! excludeRegexMatch ) )
387
+ foreach ( var rule in ruleDictionary . Keys )
388
+ {
389
+ List < object > verboseOrErrors = ruleDictionary [ rule ] ;
390
+ WriteVerbose ( verboseOrErrors [ 0 ] as string ) ;
391
+ if ( verboseOrErrors . Count == 2 )
386
392
{
387
- WriteVerbose ( string . Format ( CultureInfo . CurrentCulture , Strings . VerboseRunningMessage , scriptRule . GetName ( ) ) ) ;
388
-
389
- // Ensure that any unhandled errors from Rules are converted to non-terminating errors
390
- // We want the Engine to continue functioning even if one or more Rules throws an exception
391
- try
392
- {
393
- var records = Helper . Instance . SuppressRule ( scriptRule . GetName ( ) , ruleSuppressions , scriptRule . AnalyzeScript ( ast , filePath ) . ToList ( ) ) ;
394
- diagnostics . AddRange ( records . Item2 ) ;
395
- suppressed . AddRange ( records . Item1 ) ;
396
- }
397
- catch ( Exception scriptRuleException )
398
- {
399
- WriteError ( new ErrorRecord ( scriptRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , filePath ) ) ;
400
- }
393
+ WriteError ( verboseOrErrors [ 1 ] as ErrorRecord ) ;
401
394
}
402
395
}
403
396
}
@@ -437,8 +430,14 @@ private void AnalyzeFile(string filePath)
437
430
try
438
431
{
439
432
var records = Helper . Instance . SuppressRule ( tokenRule . GetName ( ) , ruleSuppressions , tokenRule . AnalyzeTokens ( tokens , filePath ) . ToList ( ) ) ;
440
- diagnostics . AddRange ( records . Item2 ) ;
441
- suppressed . AddRange ( records . Item1 ) ;
433
+ foreach ( var record in records . Item2 )
434
+ {
435
+ diagnostics . Add ( record ) ;
436
+ }
437
+ foreach ( var suppressedRec in records . Item1 )
438
+ {
439
+ suppressed . Add ( suppressedRec ) ;
440
+ }
442
441
}
443
442
catch ( Exception tokenRuleException )
444
443
{
@@ -489,8 +488,14 @@ private void AnalyzeFile(string filePath)
489
488
try
490
489
{
491
490
var records = Helper . Instance . SuppressRule ( dscResourceRule . GetName ( ) , ruleSuppressions , dscResourceRule . AnalyzeDSCClass ( ast , filePath ) . ToList ( ) ) ;
492
- diagnostics . AddRange ( records . Item2 ) ;
493
- suppressed . AddRange ( records . Item1 ) ;
491
+ foreach ( var record in records . Item2 )
492
+ {
493
+ diagnostics . Add ( record ) ;
494
+ }
495
+ foreach ( var suppressedRec in records . Item1 )
496
+ {
497
+ suppressed . Add ( suppressedRec ) ;
498
+ }
494
499
}
495
500
catch ( Exception dscResourceRuleException )
496
501
{
@@ -532,8 +537,14 @@ private void AnalyzeFile(string filePath)
532
537
try
533
538
{
534
539
var records = Helper . Instance . SuppressRule ( dscResourceRule . GetName ( ) , ruleSuppressions , dscResourceRule . AnalyzeDSCResource ( ast , filePath ) . ToList ( ) ) ;
535
- diagnostics . AddRange ( records . Item2 ) ;
536
- suppressed . AddRange ( records . Item1 ) ;
540
+ foreach ( var record in records . Item2 )
541
+ {
542
+ diagnostics . Add ( record ) ;
543
+ }
544
+ foreach ( var suppressedRec in records . Item1 )
545
+ {
546
+ suppressed . Add ( suppressedRec ) ;
547
+ }
537
548
}
538
549
catch ( Exception dscResourceRuleException )
539
550
{
@@ -573,15 +584,20 @@ private void AnalyzeFile(string filePath)
573
584
}
574
585
}
575
586
576
- diagnostics . AddRange ( ScriptAnalyzer . Instance . GetExternalRecord ( ast , tokens , exRules . ToArray ( ) , this , fileName ) ) ;
587
+ foreach ( var record in ScriptAnalyzer . Instance . GetExternalRecord ( ast , tokens , exRules . ToArray ( ) , this , fileName ) )
588
+ {
589
+ diagnostics . Add ( record ) ;
590
+ }
577
591
}
578
592
579
593
#endregion
580
594
595
+ IEnumerable < DiagnosticRecord > diagnosticsList = diagnostics ;
596
+
581
597
if ( severity != null )
582
598
{
583
599
var diagSeverity = severity . Select ( item => Enum . Parse ( typeof ( DiagnosticSeverity ) , item , true ) ) ;
584
- diagnostics = diagnostics . Where ( item => diagSeverity . Contains ( item . Severity ) ) . ToList ( ) ;
600
+ diagnosticsList = diagnostics . Where ( item => diagSeverity . Contains ( item . Severity ) ) ;
585
601
}
586
602
587
603
//Output through loggers
@@ -596,14 +612,73 @@ private void AnalyzeFile(string filePath)
596
612
}
597
613
else
598
614
{
599
- foreach ( DiagnosticRecord diagnostic in diagnostics )
615
+ foreach ( DiagnosticRecord diagnostic in diagnosticsList )
600
616
{
601
617
logger . LogObject ( diagnostic , this ) ;
602
618
}
603
619
}
604
620
}
605
621
}
606
622
623
+ void bg_DoWork ( object sender , DoWorkEventArgs e )
624
+ {
625
+ bool includeRegexMatch = false ;
626
+ bool excludeRegexMatch = false ;
627
+
628
+ object [ ] parameters = e . Argument as object [ ] ;
629
+
630
+ IScriptRule scriptRule = parameters [ 0 ] as IScriptRule ;
631
+
632
+ foreach ( Regex include in includeRegexList )
633
+ {
634
+ if ( include . IsMatch ( scriptRule . GetName ( ) ) )
635
+ {
636
+ includeRegexMatch = true ;
637
+ break ;
638
+ }
639
+ }
640
+
641
+ foreach ( Regex exclude in excludeRegexList )
642
+ {
643
+ if ( exclude . IsMatch ( scriptRule . GetName ( ) ) )
644
+ {
645
+ excludeRegexMatch = true ;
646
+ break ;
647
+ }
648
+ }
649
+
650
+ List < object > result = new List < object > ( ) ;
651
+
652
+ if ( ( includeRule == null || includeRegexMatch ) && ( excludeRule == null || ! excludeRegexMatch ) )
653
+ {
654
+ //WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, scriptRule.GetName()));
655
+ result . Add ( string . Format ( CultureInfo . CurrentCulture , Strings . VerboseRunningMessage , scriptRule . GetName ( ) ) ) ;
656
+
657
+ // Ensure that any unhandled errors from Rules are converted to non-terminating errors
658
+ // We want the Engine to continue functioning even if one or more Rules throws an exception
659
+ try
660
+ {
661
+ var records = Helper . Instance . SuppressRule ( scriptRule . GetName ( ) , ruleSuppressions , scriptRule . AnalyzeScript ( ast , ast . Extent . File ) . ToList ( ) ) ;
662
+ foreach ( var record in records . Item2 )
663
+ {
664
+ diagnostics . Add ( record ) ;
665
+ }
666
+ foreach ( var suppressedRec in records . Item1 )
667
+ {
668
+ suppressed . Add ( suppressedRec ) ;
669
+ }
670
+ }
671
+ catch ( Exception scriptRuleException )
672
+ {
673
+ result . Add ( new ErrorRecord ( scriptRuleException , Strings . RuleErrorMessage , ErrorCategory . InvalidOperation , ast . Extent . File ) ) ;
674
+ }
675
+ }
676
+
677
+ ruleDictionary [ scriptRule . GetName ( ) ] = result ;
678
+
679
+ cde . Signal ( ) ;
680
+ }
681
+
607
682
#endregion
608
683
}
609
684
}
0 commit comments