Skip to content

Commit 791ee64

Browse files
Jawz84Jos Koelewijnrjmholt
authored
Add UseUsingScopeModifierInNewRunspaces rule (#1419)
* Add tests for AvoidUnInitializedVarsInNewRunspaces * Add strings for AvoidUnInitializedVarsInNewRunspaces * Add documentation * wrestling with Ast in C# - not working * Add sensible warning message * remove unnecessary boilerplate from test * clean up and finetune rule * Add RuleToTest parameter to Test-ScriptAnalyzer to aid with test driven rule development * increment rule count to fix test * add reference to rule documentation * exclude built-in variables * change using directive => scoope modifier * add tests for InlineScript, Invoke-Command and Start-(Thread)Job * add rule implementation for InlineScript, Invoke-Command and Start-(Thread)Job * Refactor and cleanup * small cleanup * explain all applicable situations in documentation * simplify code for adding sessions to dict * Revert "Add RuleToTest parameter to Test-ScriptAnalyzer to aid with test driven rule development" This reverts commit 99c2bea. Undo -RuleToTest param * Rename rule to UseUsingScopeModifierInNewRunspaces Because this has a posive ring to it and points the user to the solution * refactor grouping of script blocks by session name * Add suggested correction implementation * Add test for suggested corrections, fix typos * Refactor to AstVisitor/AstVisitor2 WIP TODO: finish refactor for `Invoke-Command -Session` logic * Update Rules/UseUsingScopeModifierInNewRunspaces.cs Co-Authored-By: Robert Holt <rjmholt@gmail.com> * Update Rules/UseUsingScopeModifierInNewRunspaces.cs Co-Authored-By: Robert Holt <rjmholt@gmail.com> * Process review comments - Always use braces with if statements - Use ast.VariablePath.UserPath instead of ast.Extent.Text - simplify return list of corrections - add TODO's fo invoke-command-session code - Add TODO for commandAst.GetCommandName() can be null - Invert if for readability * Add tests for command name and icm -session * Add icm -session logic to visitor and tidy up * fix build for windows powershell * Revert "fix build for windows powershell" This reverts commit 921c1d2. revert fix, because multiple unintended changes were pushed along with it. * Change private class to internal class for Windows PowerShell * Add logic to detect DSCScriptResource * Add tests for DSC Script resource * Enhance label test topic Co-Authored-By: Robert Holt <rjmholt@gmail.com> * repair test indentation and add newline at eof * Move testcases to BeforeAll blocks * Add documentation that DSC Script resource is supported * change string[] to IReadOnlyList<string> Co-Authored-By: Robert Holt <rjmholt@gmail.com> * extract scriptBlockPosition as a variable for readability Co-Authored-By: Robert Holt <rjmholt@gmail.com> * put arguments on their own line for readability * make visitor class a private, nested class in rule * change 'var' to type name for method calls * fix indentation for nested visitor class * Remove explicit 'ToList()' for performance Co-Authored-By: Robert Holt <rjmholt@gmail.com> * add check for strongly typed assignments * Add todo comments * refactor FindAll predicates to static methods to avoid closure allocation * Refactor GetSessionName for performance. * use full type for string expression variable Co-Authored-By: Robert Holt <rjmholt@gmail.com> * use full type name for foreach variable initialization Co-Authored-By: Robert Holt <rjmholt@gmail.com> * refactor diagnostic message out to local variable Co-Authored-By: Robert Holt <rjmholt@gmail.com> * WIP: apply review suggestions refactoring FindVarsInAssignmentAsts to return a dictionary in progress * apply review suggestions refactoredFindVarsInAssignmentAsts to return a dictionary * Fix CR/LF -> LF Co-authored-by: Jos Koelewijn <Jos.Koelewijn@ogd.nl> Co-authored-by: Robert Holt <rjmholt@gmail.com>
1 parent c49fb06 commit 791ee64

7 files changed

+940
-10
lines changed

RuleDocumentation/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
|[AvoidOverwritingBuiltInCmdlets](./AvoidOverwritingBuiltInCmdlets.md) | Warning | |
1717
|[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | |
1818
|[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | |
19+
|[UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md) | Warning | |
1920
|[AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes |
2021
|[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | |
2122
|[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# UseUsingScopeModifierInNewRunspaces
2+
3+
**Severity Level: Warning**
4+
5+
## Description
6+
7+
If a ScriptBlock is intended to be run in a new RunSpace, variables inside it should use $using: scope modifier, or be initialized within the ScriptBlock.
8+
This applies to:
9+
10+
- Invoke-Command *
11+
- Workflow { InlineScript {}}
12+
- Foreach-Object **
13+
- Start-Job
14+
- Start-ThreadJob
15+
- The `Script` resource in DSC configurations, specifically for the `GetScript`, `TestScript` and `SetScript` properties
16+
17+
\* Only with the -ComputerName or -Session parameter.
18+
\*\* Only with the -Parallel parameter
19+
20+
## How to Fix
21+
22+
Within the ScriptBlock, instead of just using a variable from the parent scope, you have to add the `using:` scope modifier to it.
23+
24+
## Example
25+
26+
### Wrong
27+
28+
```PowerShell
29+
$var = "foo"
30+
1..2 | ForEach-Object -Parallel { $var }
31+
```
32+
33+
### Correct
34+
35+
```PowerShell
36+
$var = "foo"
37+
1..2 | ForEach-Object -Parallel { $using:var }
38+
```
39+
40+
## More correct examples
41+
42+
```powershell
43+
$bar = "bar"
44+
Invoke-Command -ComputerName "foo" -ScriptBlock { $using:bar }
45+
```
46+
47+
```powershell
48+
$bar = "bar"
49+
$s = New-PSSession -ComputerName "foo"
50+
Invoke-Command -Session $s -ScriptBlock { $using:bar }
51+
```
52+
53+
```powershell
54+
# Remark: Workflow is supported on Windows PowerShell only
55+
Workflow {
56+
$foo = "foo"
57+
InlineScript { $using:foo }
58+
}
59+
```
60+
61+
```powershell
62+
$foo = "foo"
63+
Start-ThreadJob -ScriptBlock { $using:foo }
64+
Start-Job -ScriptBlock {$using:foo }
65+
```

Rules/Strings.Designer.cs

+45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rules/Strings.resx

+24-9
Original file line numberDiff line numberDiff line change
@@ -1114,12 +1114,27 @@
11141114
<value>ReviewUnusedParameter</value>
11151115
</data>
11161116
<data name="ReviewUnusedParameterDescription" xml:space="preserve">
1117-
<value>Ensure all parameters are used within the same script, scriptblock, or function where they are declared.</value>
1118-
</data>
1119-
<data name="ReviewUnusedParameterError" xml:space="preserve">
1120-
<value>The parameter '{0}' has been declared but not used. </value>
1121-
</data>
1122-
<data name="ReviewUnusedParameterName" xml:space="preserve">
1123-
<value>ReviewUnusedParameter</value>
1124-
</data>
1125-
</root>
1117+
<value>Ensure all parameters are used within the same script, scriptblock, or function where they are declared.</value>
1118+
</data>
1119+
<data name="ReviewUnusedParameterError" xml:space="preserve">
1120+
<value>The parameter '{0}' has been declared but not used. </value>
1121+
</data>
1122+
<data name="ReviewUnusedParameterName" xml:space="preserve">
1123+
<value>ReviewUnusedParameter</value>
1124+
</data>
1125+
<data name="UseUsingScopeModifierInNewRunspacesCommonName" xml:space="preserve">
1126+
<value>Use 'Using:' scope modifier in RunSpace ScriptBlocks</value>
1127+
</data>
1128+
<data name="UseUsingScopeModifierInNewRunspacesDescription" xml:space="preserve">
1129+
<value>If a ScriptBlock is intended to be run as a new RunSpace, variables inside it should use 'Using:' scope modifier, or be initialized within the ScriptBlock.</value>
1130+
</data>
1131+
<data name="UseUsingScopeModifierInNewRunspacesName" xml:space="preserve">
1132+
<value>UseUsingScopeModifierInNewRunspaces</value>
1133+
</data>
1134+
<data name="UseUsingScopeModifierInNewRunspacesError" xml:space="preserve">
1135+
<value>The variable '{0}' is not declared within this ScriptBlock, and is missing the 'Using:' scope modifier.</value>
1136+
</data>
1137+
<data name="UseUsingScopeModifierInNewRunspacesCorrectionDescription" xml:space="preserve">
1138+
<value>Replace {0} with {1}</value>
1139+
</data>
1140+
</root>

0 commit comments

Comments
 (0)