From a664c785d1a67e1d7744b1659859b27c13eb797e Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Tue, 12 May 2020 17:36:40 +0100 Subject: [PATCH 1/2] UseUsingScopeModifierInNewRunspaces: Fix ArgumentException when the same variable name is used in 2 different sessions. --- Rules/UseUsingScopeModifierInNewRunspaces.cs | 33 ++++++++++--------- ...UsingScopeModifierInNewRunspaces.tests.ps1 | 21 ++++++++++++ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Rules/UseUsingScopeModifierInNewRunspaces.cs b/Rules/UseUsingScopeModifierInNewRunspaces.cs index 1db914276..e7ef455b9 100644 --- a/Rules/UseUsingScopeModifierInNewRunspaces.cs +++ b/Rules/UseUsingScopeModifierInNewRunspaces.cs @@ -116,7 +116,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor private static readonly IEnumerable s_invokeCommandCmdletNamesAndAliases = Helper.Instance.CmdletNameAndAliases("Invoke-Command"); - private readonly Dictionary> _varsDeclaredPerSession; + private readonly Dictionary> _varsDeclaredPerSession; private readonly List _diagnosticAccumulator; @@ -127,7 +127,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor public SyntaxCompatibilityVisitor(UseUsingScopeModifierInNewRunspaces rule, string analyzedScriptPath) { _diagnosticAccumulator = new List(); - _varsDeclaredPerSession = new Dictionary>(); + _varsDeclaredPerSession = new Dictionary>(); _rule = rule; _analyzedFilePath = analyzedScriptPath; } @@ -183,7 +183,7 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA return AstVisitAction.Continue; } - IReadOnlyDictionary varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst); + HashSet varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst); if (varsInLocalAssignments != null) { AddAssignedVarsToSession(sessionName, varsInLocalAssignments); @@ -191,7 +191,7 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA GenerateDiagnosticRecords( FindNonAssignedNonUsingVarAsts( - scriptBlockExpressionAst, + scriptBlockExpressionAst, GetAssignedVarsInSession(sessionName))); return AstVisitAction.SkipChildren; @@ -205,10 +205,10 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA /// Example: `$foo = "foo"` ==> the VariableExpressionAst for $foo is returned /// /// - private static IReadOnlyDictionary FindVarsInAssignmentAsts(Ast ast) + private static HashSet FindVarsInAssignmentAsts(Ast ast) { - Dictionary variableDictionary = - new Dictionary(); + HashSet variableDictionary = + new HashSet(); // Find all variables that are assigned within this ast foreach (AssignmentStatementAst statementAst in ast.FindAll(IsAssignmentStatementAst, true)) @@ -217,11 +217,11 @@ private static IReadOnlyDictionary FindVarsInAssi { string variableName = string.Format(variable.VariablePath.UserPath, StringComparer.OrdinalIgnoreCase); - variableDictionary.Add(variableName, variable); + variableDictionary.Add(variableName); } }; - return new ReadOnlyDictionary(variableDictionary); + return variableDictionary; } /// @@ -264,14 +264,14 @@ private static bool IsAssignmentStatementAst(Ast ast) /// /// private static IEnumerable FindNonAssignedNonUsingVarAsts( - Ast ast, IReadOnlyDictionary varsInAssignments) + Ast ast, HashSet varsInAssignments) { // Find all variables that are not locally assigned, and don't have $using: scope modifier foreach (VariableExpressionAst variable in ast.FindAll(IsNonUsingNonSpecialVariableExpressionAst, true)) { var varName = string.Format(variable.VariablePath.UserPath, StringComparer.OrdinalIgnoreCase); - if (varsInAssignments.ContainsKey(varName)) + if (varsInAssignments.Contains(varName)) { yield break; } @@ -368,7 +368,7 @@ private static bool TryGetSessionNameFromInvokeCommand(CommandAst invokeCommandA /// GetAssignedVarsInSession: Retrieves all previously declared vars for a given session (as in Invoke-Command -Session $session). /// /// - private IReadOnlyDictionary GetAssignedVarsInSession(string sessionName) + private HashSet GetAssignedVarsInSession(string sessionName) { return _varsDeclaredPerSession[sessionName]; } @@ -378,16 +378,19 @@ private IReadOnlyDictionary GetAssignedVarsInSessi /// /// /// - private void AddAssignedVarsToSession(string sessionName, IReadOnlyDictionary variablesToAdd) + private void AddAssignedVarsToSession(string sessionName, HashSet variablesToAdd) { if (!_varsDeclaredPerSession.ContainsKey(sessionName)) { - _varsDeclaredPerSession.Add(sessionName, new Dictionary()); + _varsDeclaredPerSession.Add(sessionName, new HashSet()); } foreach (var item in variablesToAdd) { - _varsDeclaredPerSession[sessionName].Add(item.Key, item.Value); + if (!_varsDeclaredPerSession[sessionName].Contains(item)) + { + _varsDeclaredPerSession[sessionName].Append(item); + } } } diff --git a/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1 b/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1 index 66452baf6..87dce8e90 100644 --- a/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1 +++ b/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1 @@ -274,6 +274,27 @@ Describe "UseUsingScopeModifierInNewRunspaces" { } }' } + # Issue 1492: https://github.com/PowerShell/PSScriptAnalyzer/issues/1492 + @{ + Description = 'Does not throw when the same variable name is used in two different sessions' + ScriptBlock = @' +function Get-One{ + + Invoke-Command -Session $sourceRemoteSession { + $a = $sccmModule + foo $a + } +} + +function Get-Two{ + + Invoke-Command -Session $sourceRemoteSession { + $a = $sccmModule + foo $a + } +} +'@ + } ) } From 9ae8bcc994112ba9110ab7e6f265c6b1fb061ba8 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Tue, 12 May 2020 17:47:51 +0100 Subject: [PATCH 2/2] use .add method to fix full .net build --- Rules/UseUsingScopeModifierInNewRunspaces.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rules/UseUsingScopeModifierInNewRunspaces.cs b/Rules/UseUsingScopeModifierInNewRunspaces.cs index e7ef455b9..6d665e989 100644 --- a/Rules/UseUsingScopeModifierInNewRunspaces.cs +++ b/Rules/UseUsingScopeModifierInNewRunspaces.cs @@ -389,7 +389,7 @@ private void AddAssignedVarsToSession(string sessionName, HashSet variab { if (!_varsDeclaredPerSession[sessionName].Contains(item)) { - _varsDeclaredPerSession[sessionName].Append(item); + _varsDeclaredPerSession[sessionName].Add(item); } } }