Skip to content

Fix a custom rule path bug that prevented loading rules with version in their path. #462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 15 additions & 40 deletions Engine/ScriptAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -706,28 +706,16 @@ private List<ExternalRule> GetExternalRule(string[] moduleNames)

// Imports modules by using full path.
InitialSessionState state = InitialSessionState.CreateDefault2();
state.ImportPSModule(new string[] { moduleName });

using (System.Management.Automation.PowerShell posh =
System.Management.Automation.PowerShell.Create(state))
{
posh.AddCommand("Get-Module");
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
foreach (PSModuleInfo module in loadedModules)
posh.AddCommand("Import-Module").AddArgument(moduleName).AddParameter("PassThru");
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
if (loadedModules != null && loadedModules.Count > 0)
{
string pathToCompare = moduleName;
if (!File.GetAttributes(moduleName).HasFlag(FileAttributes.Directory))
{
pathToCompare = Path.GetDirectoryName(moduleName);
}

if (pathToCompare == Path.GetDirectoryName(module.Path))
{
shortModuleName = module.Name;
break;
}
shortModuleName = loadedModules.First().Name;
}

// Invokes Get-Command and Get-Help for each functions in the module.
posh.Commands.Clear();
posh.AddCommand("Get-Command").AddParameter("Module", shortModuleName);
Expand Down Expand Up @@ -987,34 +975,21 @@ public Dictionary<string, List<string>> CheckRuleExtension(string[] path, PathIn
{
resolvedPath = basePath
.GetResolvedPSPathFromPSPath(childPath).First().ToString();
}
}

// Import the module
InitialSessionState state = InitialSessionState.CreateDefault2();
state.ImportPSModule(new string[] { resolvedPath });

InitialSessionState state = InitialSessionState.CreateDefault2();
using (System.Management.Automation.PowerShell posh =
System.Management.Automation.PowerShell.Create(state))
{
posh.AddCommand("Get-Module");
{
posh.AddCommand("Import-Module").AddArgument(resolvedPath).AddParameter("PassThru");
Collection<PSModuleInfo> loadedModules = posh.Invoke<PSModuleInfo>();
foreach (PSModuleInfo module in loadedModules)
{
string pathToCompare = resolvedPath;
if (!File.GetAttributes(resolvedPath).HasFlag(FileAttributes.Directory))
{
pathToCompare = Path.GetDirectoryName(resolvedPath);
}

if (pathToCompare == Path.GetDirectoryName(module.Path))
{
if (module.ExportedFunctions.Count > 0)
{
validModPaths.Add(resolvedPath);
}
break;
}
}
if (loadedModules != null
&& loadedModules.Count > 0
&& loadedModules.First().ExportedFunctions.Count > 0)
{
validModPaths.Add(resolvedPath);
}
}
}
catch
Expand Down
21 changes: 19 additions & 2 deletions Tests/Engine/CustomizedRule.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Describe "Test importing correct customized rules" {

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

Expand Down Expand Up @@ -147,7 +147,7 @@ Describe "Test importing correct customized rules" {

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

It "Using IncludeDefaultRules Switch with CustomRulePath" {
Expand All @@ -164,6 +164,23 @@ Describe "Test importing correct customized rules" {
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1
$customizedRulePath.Count | Should Be 1
}

It "loads custom rules that contain version in their path" {
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomRulePath $directory\SampleRuleWithVersion\SampleRuleWithVersion
$customizedRulePath.Count | Should Be 1

$customizedRulePath = Get-ScriptAnalyzerRule -CustomRulePath $directory\SampleRuleWithVersion\SampleRuleWithVersion
$customizedRulePath.Count | Should Be 1
}

It "loads custom rules that contain version in their path with the RecurseCustomRule switch" {
$customizedRulePath = Invoke-ScriptAnalyzer $directory\TestScript.ps1 -CustomRulePath $directory\SampleRuleWithVersion -RecurseCustomRulePath
$customizedRulePath.Count | Should Be 1

$customizedRulePath = Get-ScriptAnalyzerRule -CustomRulePath $directory\SampleRuleWithVersion -RecurseCustomRulePath
$customizedRulePath.Count | Should Be 1

}
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#
# Module manifest for module 'SampleRuleWithVersion'
#

@{

# Script module or binary module file associated with this manifest.
RootModule = 'SampleRuleWithVersion.psm1'

# Version number of this module.
ModuleVersion = '1.0.0.0'

# ID used to uniquely identify this module
GUID = 'f3452359-9e01-4c64-89cc-f5bfbcee53e3'

# Author of this module
Author = ''

# Company or vendor of this module
CompanyName = ''

# Copyright statement for this module
Copyright = ''

# Description of the functionality provided by this module
Description = 'Sample PSScriptAnalyzer rule.'

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '3.0'

# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module
CLRVersion = '4.0'

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()

# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()

# Functions to export from this module
FunctionsToExport = 'Measure*'

# Cmdlets to export from this module
CmdletsToExport = '*'

# Variables to export from this module
VariablesToExport = '*'

# Aliases to export from this module
AliasesToExport = '*'

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
# FileList = @()

# 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.
PrivateData = @{

PSData = @{

# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()

# A URL to the license for this module.
# LicenseUri = ''

# A URL to the main website for this project.
# ProjectUri = ''

# A URL to an icon representing this module.
# IconUri = ''

# ReleaseNotes of this module
# ReleaseNotes = ''

} # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#Requires -Version 3.0

<#
.SYNOPSIS
Uses #Requires -RunAsAdministrator instead of your own methods.
.DESCRIPTION
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.
From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator).
Script developers does not need to write their own methods any more.
To fix a violation of this rule, please consider to use #Requires -RunAsAdministrator instead of your own methods.
.EXAMPLE
Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst
.INPUTS
[System.Management.Automation.Language.ScriptBlockAst]
.OUTPUTS
[OutputType([PSCustomObject[])]
.NOTES
None
#>
function Measure-RequiresRunAsAdministrator
{
[CmdletBinding()]
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.Language.ScriptBlockAst]
$testAst
)


$results = @()

$result = [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{"Message" = "this is help";
"Extent" = $ast.Extent;
"RuleName" = $PSCmdlet.MyInvocation.InvocationName;
"Severity" = "Warning"}

$results += $result


return $results


}
Export-ModuleMember -Function Measure*