8000 Allow `Test-ModuleManifest` to work when filename is not specified #8388 by pougetat · Pull Request #8687 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Management.Automation;
using System.Management.Automation.Internal;
using System.Collections;
using System.Collections.Generic;

//
// Now define the set of commands for manipulating modules.
Expand Down Expand Up @@ -145,23 +146,12 @@ protected override void ProcessRecord()
}
}

// RootModule can be null, empty string or point to a valid .psm1, , .cdxml, .xaml, .dll or .exe. Anything else is invalid.
if (module.RootModule != null && module.RootModule != string.Empty)
if (!HasValidRootModule(module))
{
string rootModuleExt = System.IO.Path.GetExtension(module.RootModule);
if ((!IsValidFilePath(module.RootModule, module, true) && !IsValidGacAssembly(module.RootModule)) ||
(!rootModuleExt.Equals(StringLiterals.PowerShellModuleFileExtension, StringComparison.OrdinalIgnoreCase) &&
!rootModuleExt.Equals(StringLiterals.PowerShellILAssemblyExtension, StringComparison.OrdinalIgnoreCase) &&
!rootModuleExt.Equals(StringLiterals.PowerShellCmdletizationFileExtension, StringComparison.OrdinalIgnoreCase) &&
!rootModuleExt.Equals(StringLiterals.WorkflowFileExtension, StringComparison.OrdinalIgnoreCase) &&
!rootModuleExt.Equals(StringLiterals.PowerShellILExecutableExtension, StringComparison.OrdinalIgnoreCase))
)
{
string errorMsg = StringUtil.Format(Modules.InvalidModuleManifest, module.RootModule, filePath);
var errorRecord = new ErrorRecord(new ArgumentException(errorMsg), "Modules_InvalidRootModuleInModuleManifest",
ErrorCategory.InvalidArgument, _path);
WriteError(errorRecord);
}
string errorMsg = StringUtil.Format(Modules.InvalidModuleManifest, module.RootModule, filePath);
var errorRecord = new ErrorRecord(new ArgumentException(errorMsg), "Modules_InvalidRootModuleInModuleManifest",
ErrorCategory.InvalidArgument, _path);
WriteError(errorRecord);
}

Hashtable data = null;
Expand Down Expand Up @@ -302,6 +292,60 @@ protected override void ProcessRecord()
}
}

// All module extensions except ".psd1" are valid RootModule extensions
private static readonly IReadOnlyList<string> s_validRootModuleExtensions = ModuleIntrinsics.PSModuleExtensions
.Where(ext => !string.Equals(ext, StringLiterals.PowerShellDataFileExtension, StringComparison.OrdinalIgnoreCase))
.ToArray();

/// <summary>
/// Checks whether the RootModule field of a module is valid or not.
/// Valid root modules are:
/// - null
/// - Empty string
/// - A valid non-psd1 module file (psm1, cdxml, xaml, dll), as name with extension, name without extension, or path.
/// </summary>
/// <param name="module">The module for which we want to check the validity of the root module.</param>
/// <returns>True if the root module is valid, false otherwise.&l 10BC0 t;/returns>
private bool HasValidRootModule(PSModuleInfo module)
{
// Empty/null root modules are allowed
if (string.IsNullOrEmpty(module.RootModule))
{
return true;
}

// GAC assemblies are allowed
if (IsValidGacAssembly(module.RootModule))
{
return true;
}

// Check for extensions
string rootModuleExt = System.IO.Path.GetExtension(module.RootModule);
if (!string.IsNullOrEmpty(rootModuleExt))
{
// Check that the root module's extension is an allowed one
if (!s_validRootModuleExtensions.Contains(rootModuleExt, StringComparer.OrdinalIgnoreCase))
{
return false;
}

// Check the file path of the full root module
return IsValidFilePath(module.RootModule, module, verifyPathScope: true);
}

// We have no extension, so we need to check all of them
foreach (string extension in s_validRootModuleExtensions)
{
if (IsValidFilePath(module.RootModule + extension, module, verifyPathScope: true))
{
return true;
}
}

return false;
}

/// <summary>
/// Check if the given path is valid.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions test/powershell/engine/Module/TestModuleManifest.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ Describe "Test-ModuleManifest tests" -tags "CI" {
$moduleManifest.RootModule | Should -Be $rootModuleValue
}

It "module manifest containing valid rootmodule without specifying .psm1 extension succeeds" {

$rootModuleFileName = "bar.psm1";
New-Item -ItemType File -Path testdrive:/module/$rootModuleFileName > $null
New-ModuleManifest -Path $testModulePath -RootModule "bar"
$moduleManifest = Test-ModuleManifest -Path $testModulePath -ErrorAction Stop
$moduleManifest | Should -BeOfType System.Management.Automation.PSModuleInfo
$moduleManifest.RootModule | Should -Be "bar"
}

It "module manifest containing valid processed empty rootmodule file type fails: <rootModuleValue>" -TestCases (
@{rootModuleValue = "foo.cdxml"; error = "System.Xml.XmlException"}, # fails when cmdlet tries to read it as XML
@{rootModuleValue = "foo.xaml"; error = "Modules_WorkflowModuleNotSupported"} # not supported on PowerShell Core
Expand Down
0