Skip to content

Exclude dependency from RequiredModules when listed under ExternalModuleDependencies#1973

Open
anamnavi wants to merge 6 commits into
masterfrom
bugfix-externalmoduledependecies
Open

Exclude dependency from RequiredModules when listed under ExternalModuleDependencies#1973
anamnavi wants to merge 6 commits into
masterfrom
bugfix-externalmoduledependecies

Conversation

@anamnavi
Copy link
Copy Markdown
Member

@anamnavi anamnavi commented Apr 9, 2026

PSResourceGet currently requires all modules to be found/installed if present under RequiredModules, even if additionally present under ExternalModuleDependencies. RequiredModules is referred to for the following operations: Install-PSResource, Publish-PSResource and Import-Module.

Previously, PSResourceGet expected the user to not list an external dependency under RequiredModules but this breaks Import-Module. This PR addresses a fix for Install-PSResource. If the module is listed under ExternalModuleDependencies, it is skipped during installation and a verbose message is written. As the ExternalModuleDependencies metadata is not returned by the PSGallery server during Find call, it must be retrieved from the .psd1 or .ps1 metadata file for a PSResource.

#1809 also discusses checking the PSModulePath for an ExternalModule dependency and warning the user accordingly, but this PR does not address this yet.

PR Summary

PR Context

Resolves #1809

PR Checklist

@anamnavi
Copy link
Copy Markdown
Member Author

anamnavi commented Apr 9, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@anamnavi anamnavi changed the title Do not require a dependency module in RequiredModules if listed under ExternalModuleDependencies Exclude dependency from RequiredModules when listed under ExternalModuleDependencies Apr 9, 2026
@anamnavi
Copy link
Copy Markdown
Member Author

anamnavi commented May 7, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Comment thread src/code/FindHelper.cs Outdated
Comment thread src/code/InstallHelper.cs Outdated
@anamnavi anamnavi requested a review from adityapatwardhan May 11, 2026 19:24
Copilot AI review requested due to automatic review settings May 20, 2026 00:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses dependency-resolution failures when a module lists the same dependency under RequiredModules and ExternalModuleDependencies, by skipping those “external” dependencies during install/save and by excluding them from publish-time dependency validation.

Changes:

  • Read ExternalModuleDependencies from extracted module/script metadata during install/save and skip those dependencies during dependency discovery.
  • Surface ExternalModuleDependencies from PrivateData.PSData into publish metadata so publish-time required module parsing can remove them.
  • Add Pester coverage for install/save/publish scenarios involving external module dependencies.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/SavePSResourceTests/SavePSResourceV2.Tests.ps1 Adds Save-PSResource test coverage for skipping external module dependencies.
test/PublishPSResourceTests/PublishPSResource.Tests.ps1 Adds publish test ensuring external deps in RequiredModules don’t block publishing.
test/InstallPSResourceTests/InstallPSResourceV2Server.Tests.ps1 Adds Install-PSResource test coverage for skipping external module dependencies.
src/code/PublishHelper.cs Extracts ExternalModuleDependencies into parsed metadata so required-module parsing can remove them.
src/code/InstallHelper.cs Extracts external deps from manifests/scripts and threads them through install/save dependency processing.
src/code/FindHelper.cs Adds external-dependency skip logic to dependency discovery.
Comments suppressed due to low confidence (1)

src/code/InstallHelper.cs:1220

  • CreateMetadataXMLFile is always called with isModule: true, even when the package is a script. That will generate module-style metadata (PSGetModuleInfo.xml) for scripts and misrepresent the saved artifact. Pass the computed isModule value instead so scripts get the correct *_InstalledScriptInfo.xml format.
                string installPath = _pathsToInstallPkg.First();
                if (_includeXml)
                {
                    if (!CreateMetadataXMLFile(tempInstallPath, installPath, pkgToInstall, isModule: true, out error))
                    {
                        return false;
                    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/code/InstallHelper.cs
if (!File.Exists(moduleManifest))
{
error = new ErrorRecord(
new ArgumentException("Package '{pkgName}' could not be installed: Module manifest file: {moduleManifest} does not exist. This is not a valid PowerShell module."),
Comment thread src/code/InstallHelper.cs
Comment on lines +1632 to +1652
Hashtable privateData = moduleMetadata.ContainsKey("PrivateData") ? moduleMetadata["PrivateData"] as Hashtable : new Hashtable(StringComparer.OrdinalIgnoreCase);
Hashtable psData = privateData.ContainsKey("PSData") ? privateData["PSData"] as Hashtable : new Hashtable(StringComparer.OrdinalIgnoreCase);
object[] externalModDepObjects = psData.ContainsKey("ExternalModuleDependencies") ? psData["ExternalModuleDependencies"] as object[] : new object[0];
if (externalModDepObjects != null)
{
foreach (var dep in externalModDepObjects)
{
string dependencyName = dep as string;
if (dependencyName.Contains("="))
{
error = new ErrorRecord(
new ArgumentException($"Package '{pkgName}' could not be installed: ExternalModuleDependencies should only contain module names, not other metadata. Invalid entry: '{dependencyName}'"),
"ExternalModuleDependencyInvalidEntry",
ErrorCategory.ReadError,
_cmdletPassedIn);

return false;
}

externalModuleDependenciesForPkg.Add(dependencyName);
}
Comment thread src/code/InstallHelper.cs
{
foreach (var dep in externalModDepObjects)
{
string dependencyName = dep as string;
Comment thread src/code/FindHelper.cs
Comment on lines +1113 to 1120
if (externalModuleDependencies.Contains(dep.Name, StringComparer.OrdinalIgnoreCase))
{
_cmdletPassedIn.WriteVerbose($"Dependency '{dep.Name}' is listed as an external module dependency, skipping search/install for this dependency.");
continue;
}

string[] emptyExternalModuleDependencies = Utils.EmptyStrArray;
if (dep.VersionRange.Equals(VersionRange.All))
Comment thread src/code/PublishHelper.cs
Comment on lines +888 to 891
requiredModules = new Hashtable(StringComparer.OrdinalIgnoreCase);

if (parsedMetadataHash == null || parsedMetadataHash.Count == 0)
{
Comment thread src/code/PublishHelper.cs
Comment on lines +951 to +955
if (psData["ExternalModuleDependencies"] is string externalModuleDepNameStr)
{
parsedMetadataHash["ExternalModuleDependencies"] = new string[]{ externalModuleDepNameStr };
}
else if(psData["ExternalModuleDependencies"] is string[] externalModuleDepNameArr)
Comment on lines +218 to +222
It "Save resource and dependency, while skipping dependency that is listed as external module dependency" {
$testParentModule = "test_module_ext_dep"
$requiredDependency = "test_module10"
$res = Save-PSresource -Name "test_module_ext_dep" -Repository $PSGalleryName -Path $SaveDir -TrustRepository -PassThru
$res.Name | Should -Contain $testParentModule
It "Install resource and dependency, while skipping dependency that is listed as external module dependency" {
$testParentModule = "test_module_ext_dep"
$requiredDependency = "test_module10"
$res = Install-PSresource -Name "test_module_ext_dep" -Repository $PSGalleryName -TrustRepository -PassThru
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Install-PSResource fails with ExternalModuleDependencies

3 participants