diff --git a/src/WebJobs.Script/Description/PowerShell/PowerShellFunctionInvoker.cs b/src/WebJobs.Script/Description/PowerShell/PowerShellFunctionInvoker.cs index ccc000af09..d3ba3bfa32 100644 --- a/src/WebJobs.Script/Description/PowerShell/PowerShellFunctionInvoker.cs +++ b/src/WebJobs.Script/Description/PowerShell/PowerShellFunctionInvoker.cs @@ -87,7 +87,9 @@ private async Task> InvokePowerShellScript(Diction System.Management.Automation.PowerShell.Create()) { powerShellInstance.Runspace = runspace; - _moduleFiles = GetModuleFilePaths(_host.ScriptConfig.RootScriptPath, _functionName); + _moduleFiles = FindDuplicateModules(GetModuleFilePaths(_host.ScriptConfig.RootScriptPath, _functionName), _host.ScriptConfig.RootScriptPath, _functionName); + // Remove duplicates from _moduleFiles and only keep the ones closest to the Function in moduleDirectory + if (_moduleFiles.Any()) { powerShellInstance.AddCommand("Import-Module").AddArgument(_moduleFiles); @@ -261,18 +263,58 @@ internal static List GetModuleFilePaths(string rootScriptPath, string fu { List modulePaths = new List(); string functionFolder = Path.Combine(rootScriptPath, functionName); + string rootModuleDirectory = Path.Combine(rootScriptPath, PowerShellConstants.ModulesFolderName); string moduleDirectory = Path.Combine(functionFolder, PowerShellConstants.ModulesFolderName); - if (Directory.Exists(moduleDirectory)) + modulePaths.AddRange(AddToModulePaths(rootModuleDirectory, moduleDirectory)); + return modulePaths; + } + + internal static List AddToModulePaths(params string[] directories) + { + List paths = new List(); + foreach (string directory in directories) { - modulePaths.AddRange(Directory.GetFiles(moduleDirectory, - PowerShellConstants.ModulesManifestFileExtensionPattern)); - modulePaths.AddRange(Directory.GetFiles(moduleDirectory, - PowerShellConstants.ModulesBinaryFileExtensionPattern)); - modulePaths.AddRange(Directory.GetFiles(moduleDirectory, - PowerShellConstants.ModulesScriptFileExtensionPattern)); + if (Directory.Exists(directory)) + { + paths.AddRange(Directory.GetFiles(directory, + PowerShellConstants.ModulesManifestFileExtensionPattern, + SearchOption.AllDirectories)); + paths.AddRange(Directory.GetFiles(directory, + PowerShellConstants.ModulesBinaryFileExtensionPattern, + SearchOption.AllDirectories)); + paths.AddRange(Directory.GetFiles(directory, + PowerShellConstants.ModulesScriptFileExtensionPattern, + SearchOption.AllDirectories)); + } } + return paths; + } - return modulePaths; + internal static List FindDuplicateModules(List foundModules, string rootScriptPath, string functionName) + { + List moduleFileNames = new List(); + string functionFolder = Path.Combine(rootScriptPath, functionName); + string rootModuleDirectory = Path.Combine(rootScriptPath, PowerShellConstants.ModulesFolderName); + string moduleDirectory = Path.Combine(functionFolder, PowerShellConstants.ModulesFolderName); + + foreach (string entry in foundModules) + { + moduleFileNames.Add(Path.GetFileName(entry)); + } + + List distinctModuleFiles = moduleFileNames.Distinct().ToList(); + + foreach (string distinctModuleFile in distinctModuleFiles) + { + string potentialModule = Path.Combine(moduleDirectory, distinctModuleFile); + string result = foundModules.SingleOrDefault(s => s == potentialModule); + if (result != null) + { + foundModules.Remove(Path.Combine(rootModuleDirectory, distinctModuleFile)); + } + } + return foundModules; } + } } diff --git a/test/WebJobs.Script.Tests/Description/PowerShell/PowerShellInvokerTests.cs b/test/WebJobs.Script.Tests/Description/PowerShell/PowerShellInvokerTests.cs index 7af142c45c..2231333b71 100644 --- a/test/WebJobs.Script.Tests/Description/PowerShell/PowerShellInvokerTests.cs +++ b/test/WebJobs.Script.Tests/Description/PowerShell/PowerShellInvokerTests.cs @@ -37,6 +37,17 @@ public void GetModuleFilePaths() } } + [Fact] + public void FindDuplicateModules() + { + List actualModules = PowerShellFunctionInvoker.FindDuplicateModules(PowerShellFunctionInvoker.GetModuleFilePaths(_fixture.TestRootScriptPath, _fixture.TestFunctionName), _fixture.TestRootScriptPath, _fixture.TestFunctionName); + Assert.Equal(_fixture.ExpectedNumberOfImportedModules, actualModules.Count); + foreach (var actualModule in actualModules) + { + Assert.True(_fixture.TestModulesPath.Contains(actualModule)); + } + } + [Fact] public void GetRelativePath() { @@ -90,6 +101,9 @@ public Fixture() TestRootScriptPath = Path.Combine(TestHelpers.FunctionsTestDirectory, "Functions"); TestFunctionRoot = Path.Combine(TestRootScriptPath, TestFunctionName); TestModulesRoot = Path.Combine(TestFunctionRoot, "modules"); + // The number of imported modules is expected to be 6, as the "manifest-module.psd1" in RootTestModules + // should be ignored when importing. So the 7 available modules should end up being 6. + ExpectedNumberOfImportedModules = 6; TestScriptPath = CreateScriptFile(TestFunctionRoot); @@ -100,7 +114,15 @@ public Fixture() "manifest-module.psd1" }; - TestModulesPath = CreateModuleFiles(TestModulesRoot, TestModules); + RootTestModules = new string[] + { + "root-script-module.psm1", + "root-binary-module.dll", + "root-manifest-module.psd1", + "manifest-module.psd1" + }; + + TestModulesPath = CreateModuleFiles(TestModulesRoot, RootTestModules, TestModules); } public string TestFunctionRoot { get; private set; } @@ -115,9 +137,12 @@ public Fixture() public string[] TestModules { get; private set; } + public string[] RootTestModules { get; private set; } + public string TestModulesRoot { get; private set; } public List TestModulesPath { get; set; } + public int ExpectedNumberOfImportedModules { get; set; } public void Dispose() { @@ -154,13 +179,20 @@ public string CreateScriptFile(string scriptRoot) return path; } - public List CreateModuleFiles(string moduleRoot, string[] modules) + public List CreateModuleFiles(string moduleRoot, string[] rootModules, string[] modules) { if (!Directory.Exists(moduleRoot)) { Directory.CreateDirectory(moduleRoot); } + string moduleDirinRoot = TestRootScriptPath + "\\modules"; + + if (!Directory.Exists(moduleDirinRoot)) + { + Directory.CreateDirectory(moduleDirinRoot); + } + List modulesPath = new List(); foreach (var module in modules) { @@ -177,6 +209,21 @@ public List CreateModuleFiles(string moduleRoot, string[] modules) modulesPath.Add(path); } + foreach (var rootModule in rootModules) + { + string path = Path.Combine(moduleDirinRoot, rootModule); + if (!File.Exists(path)) + { + // Create a file to write to. + using (StreamWriter sw = File.CreateText(path)) + { + sw.WriteLine(string.Format("This is a {0} file.", rootModule)); + } + } + + modulesPath.Add(path); + } + return modulesPath; } }