diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index df11bf9d8..1e7227b47 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -706,28 +706,16 @@ private List 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 loadedModules = posh.Invoke(); - foreach (PSModuleInfo module in loadedModules) + posh.AddCommand("Import-Module").AddArgument(moduleName).AddParameter("PassThru"); + Collection loadedModules = posh.Invoke(); + 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); @@ -987,34 +975,21 @@ public Dictionary> 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 loadedModules = posh.Invoke(); - 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 diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 6c3cb10e9..937587993 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -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 } } @@ -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" { @@ -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 + + } } } diff --git a/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psd1 b/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psd1 new file mode 100644 index 000000000..be3c1192f --- /dev/null +++ b/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psd1 @@ -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 = '' + +} \ No newline at end of file diff --git a/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psm1 b/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psm1 new file mode 100644 index 000000000..cc94c6b1b --- /dev/null +++ b/Tests/Engine/SampleRuleWithVersion/SampleRuleWithVersion/1.0.0.0/SampleRuleWithVersion.psm1 @@ -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* \ No newline at end of file