Added PSUseFullyQualifiedCmdletNames rule with fix capabilities
PR Summary
Add new diagnostic rule PSUseFullyQualifiedCmdletNames to replace aliases and unqualified cmdlet names with fully qualified versions (e.g., ModuleName\CmdletName).
This rule addresses a common pain point in PowerShell scripting where cmdlet names without module prefixes can lead to ambiguity, especially in environments with multiple modules exporting similarly named cmdlets. By enforcing fully qualified names, the rule provides the following benefits:
- Automatic module loading: PowerShell will auto-load the specified module if it's not already loaded when the qualified cmdlet is invoked.
- Enhanced safety: Prevents accidental execution of the wrong cmdlet due to name conflicts across modules, reducing runtime errors.
- Improved readability and maintainability: Explicit module references make the code's intent clearer, aiding in code reviews and long-term upkeep.
- Better portability: Scripts become more reliable across different PowerShell environments or versions where module availability might vary.
- Reduced ambiguity: Helps avoid issues with alias resolution or unqualified names that might resolve differently based on session state.
- Facilitates advanced editor features: Supports better IntelliSense, auto-completion, and static analysis in tools like VS Code.
This change directly relates to PowerShell/PSScriptAnalyzer#2123, where the PowerShell extension for VS Code has been reported to unexpectedly remove module prefixes (e.g., converting MicrosoftTeams\Get-CsLisCivicAddress to Get-CsLisCivicAddress) during code formatting, potentially introducing ambiguities and runtime issues in scripts. This new rule enables users to automatically add or restore fully qualified cmdlet names during analysis or formatting, helping to repair the damage caused by such removals and promoting safer, more explicit scripting practices.
Implemented in Rules/UseFullyQualifiedCmdletNames.cs, with accompanying tests in the test suite to verify replacement logic for aliases (e.g., ls → Microsoft.PowerShell.Management\Get-ChildItem) and unqualified cmdlets.
PR Checklist
- [x] PR has a meaningful title
- Use the present tense and imperative mood when describing your changes
- [x] Summarized changes
- [x] Change is not breaking
- [x] Make sure all
.cs,.ps1and.psm1files have the correct copyright header - [x] Make sure you've added a new test if existing tests do not effectively test the code changed and/or updated documentation
- [x] 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.
- If the PR is work in progress, please add the prefix
@microsoft-github-policy-service agree
I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree company="Microsoft"
@genXdev please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
@microsoft-github-policy-service agree [company="{your company}"]Options:
- (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
- (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"Contributor License Agreement
@microsoft-github-policy-service agree
I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree company="Microsoft"
👋 Hey @genXdev, could you please add your tests and docs to the PR for your new rule? If you're still working on it, please title the PR as WIP and mark as draft.
My initial thoughts on this:
-
This shouldn't be a default rule. I would expect most people would find this behaviour undesirable - it makes even simple scripts incredibly verbose. My suggestion would be to make it a configurable rule, disabled by default. This allows those that want this behaviour to opt into it and still benefit from your hard work. See something like UseSingularNouns as an example for making a rule configurable and offering settings.
-
If you made the rule configurable, you could add a setting for something like
IgnoredModules\IgnoredNamespaces. For commands in those modules (i.e.Microsoft.PowerShell.ManagementandMicrosoft.PowerShell.Utility) the rule would not expand them into their fully qualified names. This could help with some of the verbosity while still retaining the value you're after. -
Looking through the context of the issue raised in the VSCode-PowerShell project, I'm not sure that this rule resolves that original issue (not that that's your stated goal). I think that, depending on order of rule execution/formatting, if your rule runs first to expand the command names to their fully qualified names - then the faulty rule runs to "correct" them - your hard work is undone. If it runs afterward it's simply masking that erroneous behaviour which will still be happening.
-
The rule name is inconsistent in the PR title (
...FullQualified...vs...FullyQualified...).
👋 Hey @genXdev, could you please add your tests and docs to the PR for your new rule? If you're still working on it, please title the PR as WIP and mark as draft.
I have committed them; https://github.com/PowerShell/PSScriptAnalyzer/commit/971f02bb1ee6546eedce761570e75630619e5263
My initial thoughts on this:
- This shouldn't be a default rule. I would expect most people would find this behaviour undesirable - it makes even simple scripts incredibly verbose. My suggestion would be to make it a configurable rule, disabled by default. This allows those that want this behaviour to opt into it and still benefit from your hard work. See something like UseSingularNouns as an example for making a rule configurable and offering settings.
Whatever you think is best.
- If you made the rule configurable, you could add a setting for something like
IgnoredModules\IgnoredNamespaces. For commands in those modules (i.e.Microsoft.PowerShell.ManagementandMicrosoft.PowerShell.Utility) the rule would not expand them into their fully qualified names. This could help with some of the verbosity while still retaining the value you're after.
If this still desirable, I'll add them, let me know.
- Looking through the context of the issue raised in the VSCode-PowerShell project, I'm not sure that this rule resolves that original issue (not that that's your stated goal). I think that, depending on order of rule execution/formatting, if your rule runs first to expand the command names to their fully qualified names - then the faulty rule runs to "correct" them - your hard work is undone. If it runs afterward it's simply masking that erroneous behaviour which will still be happening.
Haven't tested that, for fixing damage, I only enabled my new rule with -Fix
Maybe not the place to mention it, but analyzing 100+ script files at once, I sometimes see 'Collection modified' concurrency exceptions. I think it is because of SSADictionary, VariablesDictionary, VariableAnalysisDetails in .\Engine\VariableAnalysisBase.cs
Also added 'IgnoredModules' parameter and updated tests and docs accordingly
Sorry it's taken so long. Agree to not enable it by default but otherwise happy to have it. I know some module owners do this for performance reasons and replace commands with the full version as part of their build process. @genXdev can you resolve the merge conflict please, I will then greenlight the running of the CI test suite
Sorry it's taken so long. Agree to not enable it by default but otherwise happy to have it. I know some module owners do this for performance reasons and replace commands with the full version as part of their build process. @genXdev can you resolve the merge conflict please, I will then greenlight the running of the CI test suite
Hi @bergmeister,
I've resolved the merge conflict. The conflict was in Strings.resx where my UseFullyQualifiedCmdletNames resource entries overlapped with the new AvoidReservedWordsAsFunctionNames entries from main. I kept both sets of changes.
Merge commit: f6d123d
The branch should now be ready for CI tests to run.