diff --git a/Rules/UseUsingScopeModifierInNewRunspaces.cs b/Rules/UseUsingScopeModifierInNewRunspaces.cs index 1db914276..6d665e989 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].Add(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 + } +} +'@ + } ) }