Skip to content

Commit 8bd5a97

Browse files
author
Kapil Borle
committed
Merge pull request #462 from PowerShell/FixCustomRulePath
Fix a custom rule path bug that prevented loading rules with version in their path.
2 parents 87be819 + e2b77f2 commit 8bd5a97

File tree

4 files changed

+193
-42
lines changed

4 files changed

+193
-42
lines changed

Engine/ScriptAnalyzer.cs

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -706,28 +706,16 @@ private List<ExternalRule> GetExternalRule(string[] moduleNames)
706706

707707
// Imports modules by using full path.
708708
InitialSessionState state = InitialSessionState.CreateDefault2();
709-
state.ImportPSModule(new string[] { moduleName });
710-
711709
using (System.Management.Automation.PowerShell posh =
712710
System.Management.Automation.PowerShell.Create(state))
713711
{
714-
posh.AddCommand("Get-Module");
715-
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
716-
foreach (PSModuleInfo module in loadedModules)
712+
posh.AddCommand("Import-Module").AddArgument(moduleName).AddParameter("PassThru");
713+
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
714+
if (loadedModules != null && loadedModules.Count > 0)
717715
{
718-
string pathToCompare = moduleName;
719-
if (!File.GetAttributes(moduleName).HasFlag(FileAttributes.Directory))
720-
{
721-
pathToCompare = Path.GetDirectoryName(moduleName);
722-
}
723-
724-
if (pathToCompare == Path.GetDirectoryName(module.Path))
725-
{
726-
shortModuleName = module.Name;
727-
break;
728-
}
716+
shortModuleName = loadedModules.First().Name;
729717
}
730-
718+
731719
// Invokes Get-Command and Get-Help for each functions in the module.
732720
posh.Commands.Clear();
733721
posh.AddCommand("Get-Command").AddParameter("Module", shortModuleName);
@@ -987,34 +975,21 @@ public Dictionary<string, List<string>> CheckRuleExtension(string[] path, PathIn
987975
{
988976
resolvedPath = basePath
989977
.GetResolvedPSPathFromPSPath(childPath).First().ToString();
990-
}
978+
}
991979

992980
// Import the module
993-
InitialSessionState state = InitialSessionState.CreateDefault2();
994-
state.ImportPSModule(new string[] { resolvedPath });
995-
981+
InitialSessionState state = InitialSessionState.CreateDefault2();
996982
using (System.Management.Automation.PowerShell posh =
997983
System.Management.Automation.PowerShell.Create(state))
998-
{
999-
posh.AddCommand("Get-Module");
984+
{
985+
posh.AddCommand("Import-Module").AddArgument(resolvedPath).AddParameter("PassThru");
1000986
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
1001-
foreach (PSModuleInfo module in loadedModules)
1002-
{
1003-
string pathToCompare = resolvedPath;
1004-
if (!File.GetAttributes(resolvedPath).HasFlag(FileAttributes.Directory))
1005-
{
1006-
pathToCompare = Path.GetDirectoryName(resolvedPath);
1007-
}
1008-
1009-
if (pathToCompare == Path.GetDirectoryName(module.Path))
1010-
{
1011-
if (module.ExportedFunctions.Count > 0)
1012-
{
1013-
validModPaths.Add(resolvedPath);
1014-
}
1015-
break;
1016-
}
1017-
}
987+
if (loadedModules != null
988+
&& loadedModules.Count > 0
989+
&& loadedModules.First().ExportedFunctions.Count > 0)
990+
{
991+
validModPaths.Add(resolvedPath);
992+
}
1018993
}
1019994
}
1020995
catch

Tests/Engine/CustomizedRule.tests.ps1

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ Describe "Test importing correct customized rules" {
108108

109109
It "will show the custom rules when given glob with recurse switch" {
110110
$customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | Where-Object {$_.RuleName -eq $measure}
111-
$customizedRulePath.Count | Should be 3
111+
$customizedRulePath.Count | Should be 4
112112
}
113113
}
114114

@@ -147,7 +147,7 @@ Describe "Test importing correct customized rules" {
147147

148148
It "will show the custom rules when given glob with recurse switch" {
149149
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule* | Where-Object {$_.Message -eq $message}
150-
$customizedRulePath.Count | Should be 3
150+
$customizedRulePath.Count | Should be 4
151151
}
152152

153153
It "Using IncludeDefaultRules Switch with CustomRulePath" {
@@ -164,6 +164,23 @@ Describe "Test importing correct customized rules" {
164164
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1
165165
$customizedRulePath.Count | Should Be 1
166166
}
167+
168+
It "loads custom rules that contain version in their path" {
169+
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomRulePath $directory\SampleRuleWithVersion\SampleRuleWithVersion
170+
$customizedRulePath.Count | Should Be 1
171+
172+
$customizedRulePath = Get-ScriptAnalyzerRule -CustomRulePath $directory\SampleRuleWithVersion\SampleRuleWithVersion
173+
$customizedRulePath.Count | Should Be 1
174+
}
175+
176+
It "loads custom rules that contain version in their path with the RecurseCustomRule switch" {
177+
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomRulePath $directory\SampleRuleWithVersion -RecurseCustomRulePath
178+
$customizedRulePath.Count | Should Be 1
179+
180+
$customizedRulePath = Get-ScriptAnalyzerRule -CustomRulePath $directory\SampleRuleWithVersion -RecurseCustomRulePath
181+
$customizedRulePath.Count | Should Be 1
182+
183+
}
167184
}
168185

169186
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#
2+
# Module manifest for module 'SampleRuleWithVersion'
3+
#
4+
5+
@{
6+
7+
# Script module or binary module file associated with this manifest.
8+
RootModule = 'SampleRuleWithVersion.psm1'
9+
10+
# Version number of this module.
11+
ModuleVersion = '1.0.0.0'
12+
13+
# ID used to uniquely identify this module
14+
GUID = 'f3452359-9e01-4c64-89cc-f5bfbcee53e3'
15+
16+
# Author of this module
17+
Author = ''
18+
19+
# Company or vendor of this module
20+
CompanyName = ''
21+
22+
# Copyright statement for this module
23+
Copyright = ''
24+
25+
# Description of the functionality provided by this module
26+
Description = 'Sample PSScriptAnalyzer rule.'
27+
28+
# Minimum version of the Windows PowerShell engine required by this module
29+
PowerShellVersion = '3.0'
30+
31+
# Name of the Windows PowerShell host required by this module
32+
# PowerShellHostName = ''
33+
34+
# Minimum version of the Windows PowerShell host required by this module
35+
# PowerShellHostVersion = ''
36+
37+
# Minimum version of Microsoft .NET Framework required by this module
38+
# DotNetFrameworkVersion = ''
39+
40+
# Minimum version of the common language runtime (CLR) required by this module
41+
CLRVersion = '4.0'
42+
43+
# Processor architecture (None, X86, Amd64) required by this module
44+
# ProcessorArchitecture = ''
45+
46+
# Modules that must be imported into the global environment prior to importing this module
47+
# RequiredModules = @()
48+
49+
# Assemblies that must be loaded prior to importing this module
50+
# RequiredAssemblies = @()
51+
52+
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
53+
# ScriptsToProcess = @()
54+
55+
# Type files (.ps1xml) to be loaded when importing this module
56+
# TypesToProcess = @()
57+
58+
# Format files (.ps1xml) to be loaded when importing this module
59+
# FormatsToProcess = @()
60+
61+
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
62+
# NestedModules = @()
63+
64+
# Functions to export from this module
65+
FunctionsToExport = 'Measure*'
66+
67+
# Cmdlets to export from this module
68+
CmdletsToExport = '*'
69+
70+
# Variables to export from this module
71+
VariablesToExport = '*'
72+
73+
# Aliases to export from this module
74+
AliasesToExport = '*'
75+
76+
# List of all modules packaged with this module
77+
# ModuleList = @()
78+
79+
# List of all files packaged with this module
80+
# FileList = @()
81+
82+
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
83+
PrivateData = @{
84+
85+
PSData = @{
86+
87+
# Tags applied to this module. These help with module discovery in online galleries.
88+
# Tags = @()
89+
90+
# A URL to the license for this module.
91+
# LicenseUri = ''
92+
93+
# A URL to the main website for this project.
94+
# ProjectUri = ''
95+
96+
# A URL to an icon representing this module.
97+
# IconUri = ''
98+
99+
# ReleaseNotes of this module
100+
# ReleaseNotes = ''
101+
102+
} # End of PSData hashtable
103+
104+
} # End of PrivateData hashtable
105+
106+
# HelpInfo URI of this module
107+
# HelpInfoURI = ''
108+
109+
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
110+
# DefaultCommandPrefix = ''
111+
112+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#Requires -Version 3.0
2+
3+
<#
4+
.SYNOPSIS
5+
Uses #Requires -RunAsAdministrator instead of your own methods.
6+
.DESCRIPTION
7+
The #Requires statement prevents a script from running unless the Windows PowerShell version, modules, snap-ins, and module and snap-in version prerequisites are met.
8+
From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator).
9+
Script developers does not need to write their own methods any more.
10+
To fix a violation of this rule, please consider to use #Requires -RunAsAdministrator instead of your own methods.
11+
.EXAMPLE
12+
Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst
13+
.INPUTS
14+
[System.Management.Automation.Language.ScriptBlockAst]
15+
.OUTPUTS
16+
[OutputType([PSCustomObject[])]
17+
.NOTES
18+
None
19+
#>
20+
function Measure-RequiresRunAsAdministrator
21+
{
22+
[CmdletBinding()]
23+
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
24+
Param
25+
(
26+
[Parameter(Mandatory = $true)]
27+
[ValidateNotNullOrEmpty()]
28+
[System.Management.Automation.Language.ScriptBlockAst]
29+
$testAst
30+
)
31+
32+
33+
$results = @()
34+
35+
$result = [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{"Message" = "this is help";
36+
"Extent" = $ast.Extent;
37+
"RuleName" = $PSCmdlet.MyInvocation.InvocationName;
38+
"Severity" = "Warning"}
39+
40+
$results += $result
41+
42+
43+
return $results
44+
45+
46+
}
47+
Export-ModuleMember -Function Measure*

0 commit comments

Comments
 (0)