From ee819f6b7a5fd9a6bb2fcf59049778a1092f4282 Mon Sep 17 00:00:00 2001 From: Kapil Borle Date: Mon, 19 Dec 2016 17:05:46 -0800 Subject: [PATCH] Prevent concurrent commands in analysis services --- .../Analysis/AnalysisService.cs | 181 ++++++++++-------- 1 file changed, 106 insertions(+), 75 deletions(-) diff --git a/src/PowerShellEditorServices/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Analysis/AnalysisService.cs index d2318c446..57e1d5de8 100644 --- a/src/PowerShellEditorServices/Analysis/AnalysisService.cs +++ b/src/PowerShellEditorServices/Analysis/AnalysisService.cs @@ -26,6 +26,9 @@ public class AnalysisService : IDisposable private Runspace analysisRunspace; private PSModuleInfo scriptAnalyzerModuleInfo; + private Object runspaceLock; + private string[] activeRules; + private string settingsPath; /// /// Defines the list of Script Analyzer rules to include by default if @@ -54,7 +57,21 @@ public class AnalysisService : IDisposable /// /// Set of PSScriptAnalyzer rules used for analysis /// - public string[] ActiveRules { get; set; } + public string[] ActiveRules + { + get + { + return activeRules; + } + + set + { + lock (runspaceLock) + { + activeRules = value; + } + } + } /// /// Gets or sets the path to a settings file (.psd1) @@ -62,8 +79,17 @@ public class AnalysisService : IDisposable /// public string SettingsPath { - get; - set; + get + { + return settingsPath; + } + set + { + lock (runspaceLock) + { + settingsPath = value; + } + } } #endregion @@ -80,6 +106,7 @@ public AnalysisService(IConsoleHost consoleHost, string settingsPath = null) { try { + this.runspaceLock = new Object(); this.SettingsPath = settingsPath; this.analysisRunspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault2()); this.analysisRunspace.ThreadOptions = PSThreadOptions.ReuseThread; @@ -117,10 +144,10 @@ public ScriptFileMarker[] GetSemanticMarkers(ScriptFile file) Task.Factory.StartNew( () => { - return - GetDiagnosticRecords(file) - .Select(ScriptFileMarker.FromDiagnosticRecord) - .ToArray(); + return + GetDiagnosticRecords(file) + .Select(ScriptFileMarker.FromDiagnosticRecord) + .ToArray(); }, CancellationToken.None, TaskCreationOptions.None, @@ -143,13 +170,16 @@ public IEnumerable GetPSScriptAnalyzerRules() List ruleNames = new List(); if (scriptAnalyzerModuleInfo != null) { - using (var ps = System.Management.Automation.PowerShell.Create()) + lock (runspaceLock) { - ps.Runspace = this.analysisRunspace; - var ruleObjects = ps.AddCommand("Get-ScriptAnalyzerRule").Invoke(); - foreach (var rule in ruleObjects) + using (var ps = System.Management.Automation.PowerShell.Create()) { - ruleNames.Add((string)rule.Members["RuleName"].Value); + ps.Runspace = this.analysisRunspace; + var ruleObjects = ps.AddCommand("Get-ScriptAnalyzerRule").Invoke(); + foreach (var rule in ruleObjects) + { + ruleNames.Add((string)rule.Members["RuleName"].Value); + } } } } @@ -175,38 +205,33 @@ public void Dispose() #region Private Methods private void FindPSScriptAnalyzer() { - using (var ps = System.Management.Automation.PowerShell.Create()) + lock (runspaceLock) { - ps.Runspace = this.analysisRunspace; - - ps.AddCommand("Get-Module") - .AddParameter("ListAvailable") - .AddParameter("Name", "PSScriptAnalyzer"); - - ps.AddCommand("Sort-Object") - .AddParameter("Descending") - .AddParameter("Property", "Version"); - - ps.AddCommand("Select-Object") - .AddParameter("First", 1); + using (var ps = System.Management.Automation.PowerShell.Create()) + { + ps.Runspace = this.analysisRunspace; - var modules = ps.Invoke(); + var modules = ps.AddCommand("Get-Module") + .AddParameter("List") + .AddParameter("Name", "PSScriptAnalyzer") + .Invoke(); - var psModule = modules == null ? null : modules.FirstOrDefault(); - if (psModule != null) - { - scriptAnalyzerModuleInfo = psModule.ImmediateBaseObject as PSModuleInfo; - Logger.Write( - LogLevel.Normal, - string.Format( - "PSScriptAnalyzer found at {0}", - scriptAnalyzerModuleInfo.Path)); - } - else - { - Logger.Write( - LogLevel.Normal, - "PSScriptAnalyzer module was not found."); + var psModule = modules == null ? null : modules.FirstOrDefault(); + if (psModule != null) + { + scriptAnalyzerModuleInfo = psModule.ImmediateBaseObject as PSModuleInfo; + Logger.Write( + LogLevel.Normal, + string.Format( + "PSScriptAnalyzer found at {0}", + scriptAnalyzerModuleInfo.Path)); + } + else + { + Logger.Write( + LogLevel.Normal, + "PSScriptAnalyzer module was not found."); + } } } } @@ -215,25 +240,28 @@ private void ImportPSScriptAnalyzer() { if (scriptAnalyzerModuleInfo != null) { - using (var ps = System.Management.Automation.PowerShell.Create()) + lock (runspaceLock) { - ps.Runspace = this.analysisRunspace; + using (var ps = System.Management.Automation.PowerShell.Create()) + { + ps.Runspace = this.analysisRunspace; - var module = ps.AddCommand("Import-Module") - .AddParameter("ModuleInfo", scriptAnalyzerModuleInfo) - .AddParameter("PassThru") - .Invoke(); + var module = ps.AddCommand("Import-Module") + .AddParameter("ModuleInfo", scriptAnalyzerModuleInfo) + .AddParameter("PassThru") + .Invoke(); - if (module == null) - { - this.scriptAnalyzerModuleInfo = null; - Logger.Write(LogLevel.Warning, - String.Format("Cannot Import PSScriptAnalyzer: {0}")); - } - else - { - Logger.Write(LogLevel.Normal, - String.Format("Successfully imported PSScriptAnalyzer")); + if (module == null) + { + this.scriptAnalyzerModuleInfo = null; + Logger.Write(LogLevel.Warning, + String.Format("Cannot Import PSScriptAnalyzer: {0}")); + } + else + { + Logger.Write(LogLevel.Normal, + String.Format("Successfully imported PSScriptAnalyzer")); + } } } } @@ -268,28 +296,31 @@ private IEnumerable GetDiagnosticRecords(ScriptFile file) if (this.scriptAnalyzerModuleInfo != null) { - using (var powerShell = System.Management.Automation.PowerShell.Create()) + lock (runspaceLock) { - powerShell.Runspace = this.analysisRunspace; - Logger.Write( - LogLevel.Verbose, - String.Format("Running PSScriptAnalyzer against {0}", file.FilePath)); + using (var powerShell = System.Management.Automation.PowerShell.Create()) + { + powerShell.Runspace = this.analysisRunspace; + Logger.Write( + LogLevel.Verbose, + String.Format("Running PSScriptAnalyzer against {0}", file.FilePath)); - powerShell - .AddCommand("Invoke-ScriptAnalyzer") - .AddParameter("ScriptDefinition", file.Contents); + powerShell + .AddCommand("Invoke-ScriptAnalyzer") + .AddParameter("ScriptDefinition", file.Contents); - // Use a settings file if one is provided, otherwise use the default rule list. - if (!string.IsNullOrWhiteSpace(this.SettingsPath)) - { - powerShell.AddParameter("Settings", this.SettingsPath); - } - else - { - powerShell.AddParameter("IncludeRule", ActiveRules); - } + // Use a settings file if one is provided, otherwise use the default rule list. + if (!string.IsNullOrWhiteSpace(this.SettingsPath)) + { + powerShell.AddParameter("Settings", this.SettingsPath); + } + else + { + powerShell.AddParameter("IncludeRule", activeRules); + } - diagnosticRecords = powerShell.Invoke(); + diagnosticRecords = powerShell.Invoke(); + } } }