GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add new AvoidDynamicallyCreatingVariableNames rule by iRon7 · Pull Request #2178 · PowerShell/PSScriptAnalyzer

Conversation

@iRon7

@iRon7 iRon7 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

PR Summary

New rule to push for the use of hash tables rather than dynamically creating vriables in the general variable pool.
See also: https://stackoverflow.com/a/68830451/1701026

PR Checklist

  • PR has a meaningful title
    • Use the present tense and imperative mood when describing your changes
  • Summarized changes
  • Change is not breaking
  • Make sure all .cs, .ps1 and .psm1 files have the correct copyright header
  • Make sure you've added a new test if existing tests do not effectively test the code changed and/or updated documentation
  • This PR is ready to merge and is not Work in Progress.
    • If the PR is work in progress, please add the prefix WIP: to the beginning of the title and remove the prefix when the PR is ready.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
iRon7 added 2 commits April 21, 2026 17:21
@iRon7
1st commit
0e873c2
@iRon7
Avoid dynamic variable names rule implementation and tests
b4aa1a7
@iRon7
iRon7 requested review from a team, Christoph Bergmeister (bergmeister), Mikey Lombardi (He/Him) (michaeltlombardi) and Sean Wheeler (sdwheeler) as code owners April 22, 2026 10:30
@iRon7 iRon7 changed the title #1706AvoidDynamicVariableNames Add new AvoidDynamicVariableNames rule Apr 22, 2026
@iRon7
Removed using System.Linq; and added some tests
065c07e
@liamjpeters

Liam Peters (liamjpeters) commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

👋

I get that this rule is warning against using New-\Set-Variable with a non-constant name. What's the issue with dynamic variable names? Could someone use the variable drive and Set-Item to get around this? Something like: $name='foo'; Set-Item -Path "Variable:$name" -Value 1?

I think I have one bit of code in an internal module that this rule would flag. It basically hoists a bunch of variables into a caller-visible scope. I think it's perfectly legitimate? The gist of it is:

foreach ($name in $NamesToExpose) {
    Set-Variable -Scope Script -Name $name -Value $data[$name]
}

That aside...

This misses alias-based creation and update calls. e.g. nv -> New-Variable.

There's a helper function for this:

PSScriptAnalyzer/Engine/Helper.cs

Lines 216 to 233 in a143b9f

/// <summary>
/// Given a cmdlet, return the list of all the aliases.
/// Also include the original name in the list.
/// </summary>
/// <param name="Cmdlet">Name of the cmdlet</param>
/// <returns></returns>
public List<String> CmdletNameAndAliases(String Cmdlet)
{
List<String> results = new List<String>();
results.Add(Cmdlet);
if (CmdletToAliasDictionary.ContainsKey(Cmdlet))
{
results.AddRange(CmdletToAliasDictionary[Cmdlet]);
}
return results;
}

And a sample usage here:

PSScriptAnalyzer/Rules/AvoidGlobalAliases.cs

Lines 95 to 96 in a143b9f

var AliasList = Helper.Instance.CmdletNameAndAliases("New-Alias");
if (AliasList.Contains(commandAst.GetCommandName()))

You have the same copy-pasta in the class and AnalyzeScript doc-comment (references to reserved words as function names). There's also references to finding all of the FunctionDefinitionAst - something this rule isn't concerned with.

I know it works as you're statically invoking parameter binding - but perhaps a test which uses positional binding $myVarName = 'foo'; New-Variable $myVarName - just to future proof it against regressions outside of your code.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iRon7 iRon7 changed the title Add new AvoidDynamicVariableNames rule WIP: Add new AvoidDynamicVariableNames rule Apr 28, 2026
@iRon7

iRon7 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

Liam Peters (@liamjpeters),

Thank you for your feedback,
I will investigate your finding and further reply tomorrow.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Apr 28, 2026
Add new MissingTryBlock rule #2179
Merged
Add new InvalidMultiDotValue rule #2180
Merged
@iRon7
Covering Liam's feedback
ce37bb8
Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings April 29, 2026 09:05
Copilot started reviewing on behalf of iRon7 April 29, 2026 09:05
View session
@iRon7 iRon7 changed the title WIP: Add new AvoidDynamicVariableNames rule Add new AvoidDynamicallyCreatingVariableNames rule Apr 29, 2026
Copilot AI reviewed Apr 29, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new built-in PSScriptAnalyzer rule intended to discourage dynamically created variable names (favoring hashtables/dictionaries), along with documentation and Pester coverage.

Changes:

  • Add new AvoidDynamicallyCreatingVariableNames rule implementation and localized strings.
  • Add rule documentation page and include it in the rules index.
  • Add Pester tests covering violations, compliant cases, and suppression.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
docs/Rules/README.md Adds the new rule to the published rules list.
docs/Rules/AvoidDynamicallyCreatingVariableNames.md Introduces end-user documentation and examples for the new rule.
Tests/Rules/AvoidDynamicallyCreatingVariableNames.tests.ps1 Adds test coverage for rule detection and suppression behavior.
Rules/Strings.resx Adds name/common name/description/error strings for the rule.
Rules/AvoidDynamicallyCreatingVariableNames.cs Implements the new analyzer rule logic for detecting dynamic New-Variable -Name usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Rules/AvoidDynamicallyCreatingVariableNames.cs Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread docs/Rules/README.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread docs/Rules/AvoidDynamicallyCreatingVariableNames.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread docs/Rules/AvoidDynamicallyCreatingVariableNames.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Rules/Strings.resx Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Rules/AvoidDynamicallyCreatingVariableNames.cs Resolved

Uh oh!

There was an error while loading. Please reload this page.

@iRon7

iRon7 commented Apr 29, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Liam Peters (@liamjpeters),

What's the issue with dynamic variable names?

It is meant as a best practice guidance for users that are not known with hash tables, as in e.g. https://stackoverflow.com/q/68827910/1701026. There are probably a lot of ways around it but I am not trying to completely close the door on dynamically creating variable names, but only want to prevent beginners from unknowingly choosing the wrong direction and possibly run into a pitfall. I don't think that the audience I am trying to reach with this rule will use something like Set-Item -Path "Variable:$name" for this.

I think it's perfectly legitimate?

Yes, your example of Set-Variable is probably perfectly legitimate (I don't have the complete background). The problem here is that you can create a "New-Variable" with Set-Variable without knowing it (imho, I think this should actually return an error like "the variable doesn't exist" or require a Set-Variable -force parameter)
Anyways, I:

  • removed the Set-Variable from the scope as it might indeed lead to false positives (just as Set-Item might result in unforeseen false positives)
  • renamed the rule to AvoidDynamicallyCreatingVariableNames (I hope I have covered all references)
  • lowered the severity to Information

This misses alias-based creation and update calls

Implemented

You have the same copy-pasta in the class and AnalyzeScript doc-comment

Changed

but perhaps a test which uses positional binding

Added


And now Copilot also kicks in with suggestions... will I ever be able to finish this? 😆

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

iRon7 and others added 7 commits April 29, 2026 12:05
@iRon7
Update docs/Rules/AvoidDynamicallyCreatingVariableNames.md
8a7bbb0
Co-authored-by: Copilot <[email protected]>
@iRon7
Update docs/Rules/AvoidDynamicallyCreatingVariableNames.md
ba0f9a1
Co-authored-by: Copilot <[email protected]>
@iRon7
Update Rules/Strings.resx
680a3cc
Co-authored-by: Copilot <[email protected]>
@iRon7
Corrected alphabetical order of rules in README.md
b7b7f19
@iRon7
Corrected $ruleMessage in Test
ae989fd
Co-authored-by: Copilot <[email protected]>
@iRon7
Changed newVariableAst.Parent.Extent to newVariableAst.Extent
6fe86a9
@iRon7
Merge branch 'main' into PowerShell#1706-AvoidDynamicVariableNames2
a20bdf5
andyleejordan
Andy Jordan (andyleejordan) suggested changes May 5, 2026
View reviewed changes

@andyleejordan Andy Jordan (andyleejordan) left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks iRon7, and thanks Liam Peters (@liamjpeters) for the deep review on this one — I think your back-and-forth genuinely improved the rule (narrowing scope to New-Variable, picking up the alias coverage via Helper.CmdletNameAndAliases, dropping severity to Information). All of Liam's points look addressed.

Two follow-ups before I'm comfortable merging:

Opt-in by default. This rule is still derived from IScriptRule, which means it's enabled-by-default for everyone. For a new rule — especially one at Information severity that is going to flag any New-Variable -Name $name in dynamic-config / metaprogramming-style scripts — our convention is to ship it opt-in via ConfigurableRule with Enable = false. Same recipe as AvoidExclaimOperator. Could you switch the base class and update docs/Rules/README.md accordingly?

Second maintainer read. Now that the scope is narrowed to just New-Variable, I'd like Christoph Bergmeister (@bergmeister) or Mikey Lombardi (He/Him) (@michaeltlombardi) to weigh in on whether the rule still earns its keep at this scope, or whether it would be better recombined with the dynamic Set-Item Variable:\… form. Either answer is fine with me — just want a second pair of eyes on the design question before we land it.

Drafted by Copilot (Claude Opus 4.7)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@iRon7

iRon7 commented May 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Andy Jordan (@andyleejordan)

Opt-in by default.
...
our convention is to ship it opt-in via ConfigurableRule with Enable = false.

This morning, I have also added an additional #2183 PR.
Despite the fact that I based that one on the ConfigurableRule class, I also enabled it by default.
Now going though each PR feedback one-by-one, it gets clear that the general policy is to avoid the IScriptRule interface.
If this is a convention, I would certainly consider to put that in one of the general test so that authors do not have to revise their cs rules (and everything that comes with that, rule.md, README.md and related tests)
(and, Liam Peters (@liamjpeters), you might want to make that clear in your blogpost too.)

Although, I see the value of preferring a ConfigurableRule above a IScriptRule, I don't like the idea of disabling all new rules by default. My effort (which definitely has taken more time than anticipated at first) in writing these rules was intended to reach the PowerShell(starter) audience and prevent pitfalls (mainly by using VSCode). If those rules are disabled by default, I find it unlikely to believe that they will actually reach this audience and wonder whether this whole exercise has been a waste of time for me.
Btw, I suspect that the author of #2109 also lost his interest due to amount of effort it takes to get a formal rule PR through the process. Yet, the PSAvoidUsingNewObject rule is a perfect example where you want to wake-up the community in improving the PowerShell syntax and performance.
I was planned to finish this rule and I do see the advantage of making it configurable (I was even thinking of implementing an automated corrective action/fix), but if it also needs to be disabled by default, I won't put any effort in it...

Maybe a general solution (e.g. a setting like DisableRulesNewerThan = <date>) could supply a way out of this...

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

sdwheeler
Sean Wheeler (sdwheeler) suggested changes May 6, 2026
View reviewed changes
Comment thread docs/Rules/AvoidDynamicallyCreatingVariableNames.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread docs/Rules/AvoidDynamicallyCreatingVariableNames.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread docs/Rules/AvoidDynamicallyCreatingVariableNames.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

@iRon7 iRon7 changed the title Add new AvoidDynamicallyCreatingVariableNames rule WIP: Add new AvoidDynamicallyCreatingVariableNames rule May 7, 2026
@iRon7 iRon7 mentioned this pull request May 7, 2026
Additional settings file for developement #2184
Open
bergmeister
Christoph Bergmeister (bergmeister) reviewed May 7, 2026
View reviewed changes

@bergmeister Christoph Bergmeister (bergmeister) left a comment

Copy link
Copy Markdown
Collaborator

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure we need a rule for this to warn when using New-Variable. PowerShell's own variable nature is dynamic and it can sometimes be a blessing and sometimes unpredictable and hard for PSSA. But it's up to user, there are far more dynamic things in PowerShell that allows users to shoot into their own foot

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@iRon7

iRon7 commented May 13, 2026

Copy link
Copy Markdown
Contributor Author

Christoph Bergmeister (@bergmeister),

I am not sure we need a rule for this to warn when using New-Variable

This https://stackoverflow.com/q/68827910/1701026 StackOverflow question, shows where a novice scripter could be prevented to run into the wrong direction. But, I agree, even experienced PowerShell programmers might choose to shoot in their own foot 🤪. See: PowerShell/PowerShell#27023

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@iRon7
Made rule configurable (disabled) and updated documentation and tests…
3e546a4
… accordingly. Increased number of information tests to 20 in Get-ScriptAnalyzerRule tests.
@iRon7 iRon7 changed the title WIP: Add new AvoidDynamicallyCreatingVariableNames rule Add new AvoidDynamicallyCreatingVariableNames rule May 13, 2026
sdwheeler
Sean Wheeler (sdwheeler) approved these changes May 15, 2026
View reviewed changes

@sdwheeler Sean Wheeler (sdwheeler) left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs look good.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
andyleejordan
Andy Jordan (andyleejordan) approved these changes May 15, 2026
View reviewed changes

@andyleejordan Andy Jordan (andyleejordan) left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks iRon7 — the opt-in conversion (ConfigurableRule, Enable = false, README Information / No / Yes) and the bumped Information-rule count in the Get-ScriptAnalyzerRule test are in. Approving.

Weighing in on the design question: I agree this is a useful "best practice" rule — exactly the kind of thing I'd turn on for my own code. PowerShell's variable layer is dynamic by nature and there are other forms we don't catch (Set-Item Variable:\…, ${$name} = …, Get-Variable -Name $... | Set-…), but as an opt-in Information-severity rule narrowly scoped to New-Variable -Name $... the value/cost calculus is fine. We can extend the detection surface in follow-ups.

Heads-up: CI on the latest commit (3e546a48) is in action_required state — I'll approve the workflow run so we have a green run on file before merge.

Drafted by Copilot (Claude Opus 4.7)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
iRon7 added 2 commits May 17, 2026 10:47
@iRon7
Change rule name from PSAvoidExclaimOperator to PSAvoidDynamicallyCre…
1a59705
…atingVariableNames in documentation.
@iRon7
Merge branch 'main' into PowerShell#1706-AvoidDynamicVariableNames2
578d02f
andyleejordan
Andy Jordan (andyleejordan) approved these changes May 18, 2026
View reviewed changes
@andyleejordan
Andy Jordan (andyleejordan) merged commit 4b0117c into PowerShell:main May 18, 2026
4 checks passed

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@bergmeister Christoph Bergmeister (bergmeister) bergmeister left review comments
Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments
@michaeltlombardi Mikey Lombardi (He/Him) (michaeltlombardi) Awaiting requested review from michaeltlombardi michaeltlombardi is a code owner
+2 more reviewers
@andyleejordan Andy Jordan (andyleejordan) andyleejordan approved these changes
@sdwheeler Sean Wheeler (sdwheeler) sdwheeler approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@iRon7 @liamjpeters @andyleejordan @bergmeister @sdwheeler
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.