commit e9521d35c254d50ebb15b69841960c74a2f87a6c
parent 0073a6e184ca4dd00facfe53236237627707e26a
Author: Ruben Guerrero <rubengu@microsoft.com>
Date: Thu, 17 Aug 2023 18:00:09 -0700
PowerShellGet (#3521)
Creates new IPowerShellGet and provide a 2.2.5 implementation. This will make it easier for us to move to v3 when released.
Use Import-CliXml instead of Get-InstalledModule. We will now get the information we need for modules that were installed via Install-Module and SaveModule.
Diffstat:
5 files changed, 377 insertions(+), 170 deletions(-)
diff --git a/src/Microsoft.Management.Configuration.Processor/Constants/PowerShellConstants.cs b/src/Microsoft.Management.Configuration.Processor/Constants/PowerShellConstants.cs
@@ -44,6 +44,7 @@ namespace Microsoft.Management.Configuration.Processor.Constants
public const string InvokeDscResource = "Invoke-DscResource";
public const string SaveModule = "Save-Module";
public const string FindModule = "Find-Module";
+ public const string ImportCliXml = "Import-CliXml";
}
internal static class Parameters
diff --git a/src/Microsoft.Management.Configuration.Processor/Helpers/IPowerShellGet.cs b/src/Microsoft.Management.Configuration.Processor/Helpers/IPowerShellGet.cs
@@ -0,0 +1,91 @@
+// -----------------------------------------------------------------------------
+// <copyright file="IPowerShellGet.cs" company="Microsoft Corporation">
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+// </copyright>
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.Management.Configuration.Processor.Helpers
+{
+ using System.Management.Automation;
+ using Microsoft.PowerShell.Commands;
+
+ /// <summary>
+ /// Interface for PowerShellGet cmdlets.
+ /// </summary>
+ internal interface IPowerShellGet
+ {
+ /// <summary>
+ /// Calls Find-Module.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="moduleName">Module name.</param>
+ /// <param name="semanticVersion">Optional version.</param>
+ /// <param name="semanticMinVersion">Optional min version.</param>
+ /// <param name="semanticMaxVersion">Optional max version.</param>
+ /// <param name="repository">Optional repository.</param>
+ /// <param name="allowPrerelease">Optional allow prerelease module.</param>
+ /// <returns>Module info, null if not found.</returns>
+ PSObject? FindModule(
+ PowerShell pwsh,
+ string moduleName,
+ SemanticVersion? semanticVersion,
+ SemanticVersion? semanticMinVersion,
+ SemanticVersion? semanticMaxVersion,
+ string? repository,
+ bool? allowPrerelease);
+
+ /// <summary>
+ /// Calls Find-DscResource.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="resourceName">resource name.</param>
+ /// <param name="moduleName">Optional module name.</param>
+ /// <param name="semanticVersion">Optional version.</param>
+ /// <param name="semanticMinVersion">Optional min version.</param>
+ /// <param name="semanticMaxVersion">Optional max version.</param>
+ /// <param name="repository">Optional repository.</param>
+ /// <param name="allowPrerelease">Optional allow prerelease module.</param>
+ /// <returns>Dsc Resource info, null if not found.</returns>
+ PSObject? FindDscResource(
+ PowerShell pwsh,
+ string resourceName,
+ string? moduleName,
+ SemanticVersion? semanticVersion,
+ SemanticVersion? semanticMinVersion,
+ SemanticVersion? semanticMaxVersion,
+ string? repository,
+ bool? allowPrerelease);
+
+ /// <summary>
+ /// Calls Save-Module with module specification.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="moduleSpecification">Module specification.</param>
+ /// <param name="location">Location to save module.</param>
+ void SaveModule(PowerShell pwsh, ModuleSpecification moduleSpecification, string location);
+
+ /// <summary>
+ /// Calls Save-Module -InputObject object -Path location.
+ /// Input object must be the result of Find cmdlets of PowerShellGet.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="inputObject">Input object.</param>
+ /// <param name="location">Location to save module.</param>
+ void SaveModule(PowerShell pwsh, PSObject inputObject, string location);
+
+ /// <summary>
+ /// Calls Install-Module -InputObject object.
+ /// Input object must be the result of Find cmdlets of PowerShellGet.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="inputObject">Input object.</param>
+ void InstallModule(PowerShell pwsh, PSObject inputObject);
+
+ /// <summary>
+ /// Calls Install-Module with a module specification.
+ /// </summary>
+ /// <param name="pwsh">PowerShell instance.</param>
+ /// <param name="moduleSpecification">Module specification.</param>
+ void InstallModule(PowerShell pwsh, ModuleSpecification moduleSpecification);
+ }
+}
diff --git a/src/Microsoft.Management.Configuration.Processor/Helpers/PowerShellGetV2.cs b/src/Microsoft.Management.Configuration.Processor/Helpers/PowerShellGetV2.cs
@@ -0,0 +1,229 @@
+// -----------------------------------------------------------------------------
+// <copyright file="PowerShellGetV2.cs" company="Microsoft Corporation">
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+// </copyright>
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.Management.Configuration.Processor.Helpers
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Management.Automation;
+ using Microsoft.PowerShell.Commands;
+ using static Microsoft.Management.Configuration.Processor.Constants.PowerShellConstants;
+
+ /// <summary>
+ /// PowerShellGet implementation for 2.2.5 .
+ /// </summary>
+ internal class PowerShellGetV2 : IPowerShellGet
+ {
+ /// <inheritdoc/>
+ public PSObject? FindModule(
+ PowerShell pwsh,
+ string moduleName,
+ SemanticVersion? semanticVersion,
+ SemanticVersion? semanticMinVersion,
+ SemanticVersion? semanticMaxVersion,
+ string? repository,
+ bool? allowPrerelease)
+ {
+ bool implicitAllowPrerelease = false;
+
+ var parameters = new Dictionary<string, object>()
+ {
+ { Parameters.Name, moduleName },
+ };
+
+ if (semanticVersion != null)
+ {
+ implicitAllowPrerelease |= semanticVersion.IsPrerelease;
+ parameters.Add(Parameters.RequiredVersion, semanticVersion.ToString());
+ }
+
+ if (semanticMinVersion != null)
+ {
+ implicitAllowPrerelease |= semanticMinVersion.IsPrerelease;
+ parameters.Add(Parameters.MinimumVersion, semanticMinVersion.ToString());
+ }
+
+ if (semanticMaxVersion != null)
+ {
+ implicitAllowPrerelease |= semanticMaxVersion.IsPrerelease;
+ parameters.Add(Parameters.MaximumVersion, semanticMaxVersion.ToString());
+ }
+
+ if (!string.IsNullOrEmpty(repository))
+ {
+ parameters.Add(Parameters.Repository, repository);
+ }
+
+ if (allowPrerelease.HasValue || implicitAllowPrerelease)
+ {
+ // If explicit allowPrerelease = false don't use implicit.
+ bool allow = allowPrerelease ?? implicitAllowPrerelease;
+ parameters.Add(Parameters.AllowPrerelease, allow);
+ }
+
+ pwsh.AddCommand(Commands.FindModule)
+ .AddParameters(parameters);
+
+ return pwsh.Invoke().FirstOrDefault();
+ }
+
+ /// <inheritdoc/>
+ public PSObject? FindDscResource(
+ PowerShell pwsh,
+ string resourceName,
+ string? moduleName,
+ SemanticVersion? semanticVersion,
+ SemanticVersion? semanticMinVersion,
+ SemanticVersion? semanticMaxVersion,
+ string? repository,
+ bool? allowPrerelease)
+ {
+ var parameters = new Dictionary<string, object>()
+ {
+ { Parameters.Name, resourceName },
+ };
+
+ bool implicitAllowPrerelease = false;
+
+ if (!string.IsNullOrEmpty(moduleName))
+ {
+ parameters.Add(Parameters.ModuleName, moduleName);
+ }
+
+ if (semanticVersion != null)
+ {
+ implicitAllowPrerelease |= semanticVersion.IsPrerelease;
+ parameters.Add(Parameters.RequiredVersion, semanticVersion.ToString());
+ }
+
+ if (semanticMinVersion != null)
+ {
+ implicitAllowPrerelease |= semanticMinVersion.IsPrerelease;
+ parameters.Add(Parameters.MinimumVersion, semanticMinVersion.ToString());
+ }
+
+ if (semanticMaxVersion != null)
+ {
+ implicitAllowPrerelease |= semanticMaxVersion.IsPrerelease;
+ parameters.Add(Parameters.MaximumVersion, semanticMaxVersion.ToString());
+ }
+
+ if (!string.IsNullOrEmpty(repository))
+ {
+ parameters.Add(Parameters.Repository, repository);
+ }
+
+ if (allowPrerelease.HasValue || implicitAllowPrerelease)
+ {
+ // If explicit allowPrerelease = false don't use implicit.
+ bool allow = allowPrerelease ?? implicitAllowPrerelease;
+ parameters.Add(Parameters.AllowPrerelease, allow);
+ }
+
+ pwsh.AddCommand(Commands.FindDscResource)
+ .AddParameters(parameters);
+
+ // The result is just a PSCustomObject with a type name of Microsoft.PowerShell.Commands.PSGetDscResourceInfo.
+ // When no module is passed and a resource is not found, this will return an empty list. If a module
+ // is specified and no resource is found then it will fail earlier because of a Write-Error.
+ return pwsh.Invoke().FirstOrDefault();
+ }
+
+ /// <inheritdoc/>
+ public void SaveModule(
+ PowerShell pwsh,
+ ModuleSpecification moduleSpecification,
+ string location)
+ {
+ var parameters = new Dictionary<string, object>()
+ {
+ { Parameters.Name, moduleSpecification.Name },
+ { Parameters.Path, location },
+ };
+
+ if (moduleSpecification.Version is not null)
+ {
+ parameters.Add(Parameters.MinimumVersion, moduleSpecification.Version);
+ }
+
+ if (moduleSpecification.MaximumVersion is not null)
+ {
+ parameters.Add(Parameters.MaximumVersion, moduleSpecification.MaximumVersion);
+ }
+
+ if (moduleSpecification.RequiredVersion is not null)
+ {
+ parameters.Add(Parameters.RequiredVersion, moduleSpecification.RequiredVersion);
+ }
+
+ _ = pwsh.AddCommand(Commands.SaveModule)
+ .AddParameters(parameters)
+ .AddParameter(Parameters.Force)
+ .Invoke();
+ }
+
+ /// <inheritdoc/>
+ public void SaveModule(
+ PowerShell pwsh,
+ PSObject inputObject,
+ string location)
+ {
+ _ = pwsh.AddCommand(Commands.SaveModule)
+ .AddParameter(Parameters.Path, location)
+ .AddParameter(Parameters.InputObject, inputObject)
+ .AddParameter(Parameters.Force)
+ .Invoke();
+ }
+
+ /// <inheritdoc/>
+ public void InstallModule(
+ PowerShell pwsh,
+ PSObject inputObject)
+ {
+ // If the repository is untrusted, it will fail with:
+ // Microsoft.PowerShell.Commands.WriteErrorException : Exception calling "ShouldContinue" with "5"
+ // argument(s): "A command that prompts the user failed because the host program or the command type
+ // does not support user interaction.
+ // If its trusted, PowerShellGets adds the Force parameter to the call to PackageManager\Install-Package.
+ // TODO: Once we have policies, we should remove Force. For hosted environments and depending
+ // on the policy we will trust PSGallery when we create the Runspace or add Force here.
+ _ = pwsh.AddCommand(Commands.InstallModule)
+ .AddParameter(Parameters.InputObject, inputObject)
+ .AddParameter(Parameters.Force)
+ .Invoke();
+ }
+
+ /// <inheritdoc/>
+ public void InstallModule(
+ PowerShell pwsh,
+ ModuleSpecification moduleSpecification)
+ {
+ var parameters = new Dictionary<string, object>()
+ {
+ { Parameters.Name, moduleSpecification.Name },
+ };
+ if (moduleSpecification.Version is not null)
+ {
+ parameters.Add(Parameters.MinimumVersion, moduleSpecification.Version);
+ }
+
+ if (moduleSpecification.MaximumVersion is not null)
+ {
+ parameters.Add(Parameters.MaximumVersion, moduleSpecification.MaximumVersion);
+ }
+
+ if (moduleSpecification.RequiredVersion is not null)
+ {
+ parameters.Add(Parameters.RequiredVersion, moduleSpecification.RequiredVersion);
+ }
+
+ _ = pwsh.AddCommand(Commands.InstallModule)
+ .AddParameters(parameters)
+ .AddParameter(Parameters.Force)
+ .Invoke();
+ }
+ }
+}
diff --git a/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/HostedEnvironment.cs b/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/HostedEnvironment.cs
@@ -31,6 +31,7 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
internal class HostedEnvironment : IProcessorEnvironment
{
private readonly PowerShellConfigurationProcessorType type;
+ private readonly IPowerShellGet powerShellGet;
/// <summary>
/// Initializes a new instance of the <see cref="HostedEnvironment"/> class.
@@ -38,11 +39,17 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="type">Configuration processor type.</param>
/// <param name="dscModule">IDscModule.</param>
- public HostedEnvironment(Runspace runspace, PowerShellConfigurationProcessorType type, IDscModule dscModule)
+ public HostedEnvironment(
+ Runspace runspace,
+ PowerShellConfigurationProcessorType type,
+ IDscModule dscModule)
{
this.Runspace = runspace;
this.type = type;
this.DscModule = dscModule;
+
+ // TODO: once v3 is release implement v3 version.
+ this.powerShellGet = new PowerShellGetV2();
}
/// <inheritdoc/>
@@ -229,35 +236,29 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
/// <inheritdoc/>
public PSObject? GetInstalledModule(ModuleSpecification moduleSpecification)
{
- var parameters = new Dictionary<string, object>()
- {
- { Parameters.Name, moduleSpecification.Name },
- };
-
- if (moduleSpecification.Version is not null)
- {
- parameters.Add(Parameters.MinimumVersion, moduleSpecification.Version);
- }
-
- if (moduleSpecification.MaximumVersion is not null)
+ // Instead of Get-InstalledModule, we look for PSGetModuleInfo.xml and serialize it
+ // if found. This allow us to get the information from Install-Module and Save-Module.
+ var module = this.GetAvailableModule(moduleSpecification);
+ if (module is null)
{
- parameters.Add(Parameters.MaximumVersion, moduleSpecification.MaximumVersion);
+ return null;
}
- if (moduleSpecification.RequiredVersion is not null)
+ var getModuleInfoFile = Path.Combine(module.ModuleBase, "PSGetModuleInfo.xml");
+ if (!File.Exists(getModuleInfoFile))
{
- parameters.Add(Parameters.RequiredVersion, moduleSpecification.RequiredVersion);
+ // Keep Get-InstalledModule behaviour.
+ return null;
}
using PowerShell pwsh = PowerShell.Create(this.Runspace);
-
- var result = pwsh.AddCommand(Commands.GetInstalledModule)
- .AddParameters(parameters)
- .Invoke()
- .FirstOrDefault();
+ var installedModule = pwsh.AddCommand(Commands.ImportCliXml)
+ .AddParameter(Parameters.Path, getModuleInfoFile)
+ .Invoke()
+ .FirstOrDefault();
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
- return result;
+ return installedModule;
}
/// <inheritdoc/>
@@ -272,56 +273,16 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
return null;
}
- var semanticVersion = unitInternal.GetSemanticVersion();
- var semanticMinVersion = unitInternal.GetSemanticMinVersion();
- var semanticMaxVersion = unitInternal.GetSemanticMaxVersion();
- string? repository = unitInternal.GetDirective<string>(DirectiveConstants.Repository);
-
- bool? allowPrerelease = unitInternal.GetDirective(DirectiveConstants.AllowPrerelease);
- bool implicitAllowPrerelease = false;
-
- var parameters = new Dictionary<string, object>()
- {
- { Parameters.Name, moduleName },
- };
-
- if (semanticVersion != null)
- {
- implicitAllowPrerelease |= semanticVersion.IsPrerelease;
- parameters.Add(Parameters.RequiredVersion, semanticVersion.ToString());
- }
-
- if (semanticMinVersion != null)
- {
- implicitAllowPrerelease |= semanticMinVersion.IsPrerelease;
- parameters.Add(Parameters.MinimumVersion, semanticMinVersion.ToString());
- }
-
- if (semanticMaxVersion != null)
- {
- implicitAllowPrerelease |= semanticMaxVersion.IsPrerelease;
- parameters.Add(Parameters.MaximumVersion, semanticMaxVersion.ToString());
- }
-
- if (!string.IsNullOrEmpty(repository))
- {
- parameters.Add(Parameters.Repository, repository);
- }
-
- if (allowPrerelease.HasValue || implicitAllowPrerelease)
- {
- // If explicit allowPrerelease = false don't use implicit.
- bool allow = allowPrerelease.HasValue ? allowPrerelease.Value : implicitAllowPrerelease;
- parameters.Add(Parameters.AllowPrerelease, allow);
- }
-
using PowerShell pwsh = PowerShell.Create(this.Runspace);
- pwsh.AddCommand(Commands.FindModule)
- .AddParameters(parameters);
-
- var result = pwsh.Invoke()
- .FirstOrDefault();
+ var result = this.powerShellGet.FindModule(
+ pwsh,
+ moduleName,
+ unitInternal.GetSemanticVersion(),
+ unitInternal.GetSemanticMinVersion(),
+ unitInternal.GetSemanticMaxVersion(),
+ unitInternal.GetDirective<string>(DirectiveConstants.Repository),
+ unitInternal.GetDirective(DirectiveConstants.AllowPrerelease));
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
return result;
@@ -330,67 +291,17 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
/// <inheritdoc/>
public PSObject? FindDscResource(ConfigurationUnitInternal unitInternal)
{
- var parameters = new Dictionary<string, object>()
- {
- { Parameters.Name, unitInternal.Unit.UnitName },
- };
-
- // Don't use ModuleSpecification here. Each parameter is independent and
- // we need version even if a module was not specified.
- string? moduleName = unitInternal.GetDirective<string>(DirectiveConstants.Module);
- var semanticVersion = unitInternal.GetSemanticVersion();
- var semanticMinVersion = unitInternal.GetSemanticMinVersion();
- var semanticMaxVersion = unitInternal.GetSemanticMaxVersion();
- string? repository = unitInternal.GetDirective<string>(DirectiveConstants.Repository);
-
- bool? allowPrerelease = unitInternal.GetDirective(DirectiveConstants.AllowPrerelease);
- bool implicitAllowPrerelease = false;
-
- if (!string.IsNullOrEmpty(moduleName))
- {
- parameters.Add(Parameters.ModuleName, moduleName);
- }
-
- if (semanticVersion != null)
- {
- implicitAllowPrerelease |= semanticVersion.IsPrerelease;
- parameters.Add(Parameters.RequiredVersion, semanticVersion.ToString());
- }
-
- if (semanticMinVersion != null)
- {
- implicitAllowPrerelease |= semanticMinVersion.IsPrerelease;
- parameters.Add(Parameters.MinimumVersion, semanticMinVersion.ToString());
- }
-
- if (semanticMaxVersion != null)
- {
- implicitAllowPrerelease |= semanticMaxVersion.IsPrerelease;
- parameters.Add(Parameters.MaximumVersion, semanticMaxVersion.ToString());
- }
-
- if (!string.IsNullOrEmpty(repository))
- {
- parameters.Add(Parameters.Repository, repository);
- }
-
- if (allowPrerelease.HasValue || implicitAllowPrerelease)
- {
- // If explicit allowPrerelease = false don't use implicit.
- bool allow = allowPrerelease.HasValue ? allowPrerelease.Value : implicitAllowPrerelease;
- parameters.Add(Parameters.AllowPrerelease, allow);
- }
-
using PowerShell pwsh = PowerShell.Create(this.Runspace);
- pwsh.AddCommand(Commands.FindDscResource)
- .AddParameters(parameters);
-
- // The result is just a PSCustomObject with a type name of Microsoft.PowerShell.Commands.PSGetDscResourceInfo.
- // When no module is passed and a resource is not found, this will return an empty list. If a module
- // is specified and no resource is found then it will fail earlier because of a Write-Error.
- var result = pwsh.Invoke()
- .FirstOrDefault();
+ var result = this.powerShellGet.FindDscResource(
+ pwsh,
+ unitInternal.Unit.UnitName,
+ unitInternal.GetDirective<string>(DirectiveConstants.Module),
+ unitInternal.GetSemanticVersion(),
+ unitInternal.GetSemanticMinVersion(),
+ unitInternal.GetSemanticMaxVersion(),
+ unitInternal.GetDirective<string>(DirectiveConstants.Repository),
+ unitInternal.GetDirective(DirectiveConstants.AllowPrerelease));
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
return result;
@@ -400,12 +311,15 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
public void SaveModule(PSObject inputObject, string location)
{
using PowerShell pwsh = PowerShell.Create(this.Runspace);
+ this.powerShellGet.SaveModule(pwsh, inputObject, location);
+ this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
+ }
- _ = pwsh.AddCommand(Commands.SaveModule)
- .AddParameter(Parameters.Path, location)
- .AddParameter(Parameters.InputObject, inputObject)
- .Invoke();
-
+ /// <inheritdoc/>
+ public void SaveModule(ModuleSpecification moduleSpecification, string location)
+ {
+ using PowerShell pwsh = PowerShell.Create(this.Runspace);
+ this.powerShellGet.SaveModule(pwsh, moduleSpecification, location);
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
}
@@ -413,19 +327,7 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
public void InstallModule(PSObject inputObject)
{
using PowerShell pwsh = PowerShell.Create(this.Runspace);
-
- // If the repository is untrusted, it will fail with:
- // Microsoft.PowerShell.Commands.WriteErrorException : Exception calling "ShouldContinue" with "5"
- // argument(s): "A command that prompts the user failed because the host program or the command type
- // does not support user interaction.
- // If its trusted, PowerShellGets adds the Force parameter to the call to PackageManager\Install-Package.
- // TODO: Once we have policies, we should remove Force. For hosted environments and depending
- // on the policy we will trust PSGallery when we create the Runspace or add Force here.
- _ = pwsh.AddCommand(Commands.InstallModule)
- .AddParameter(Parameters.InputObject, inputObject)
- .AddParameter(Parameters.Force)
- .Invoke();
-
+ this.powerShellGet.InstallModule(pwsh, inputObject);
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
}
@@ -436,31 +338,8 @@ namespace Microsoft.Management.Configuration.Processor.Runspaces
if (!this.ValidateModule(moduleSpecification))
{
// Ok, we have to get it.
- var parameters = new Dictionary<string, object>()
- {
- { Parameters.Name, moduleSpecification.Name },
- };
- if (moduleSpecification.Version is not null)
- {
- parameters.Add(Parameters.MinimumVersion, moduleSpecification.Version);
- }
-
- if (moduleSpecification.MaximumVersion is not null)
- {
- parameters.Add(Parameters.MaximumVersion, moduleSpecification.MaximumVersion);
- }
-
- if (moduleSpecification.RequiredVersion is not null)
- {
- parameters.Add(Parameters.RequiredVersion, moduleSpecification.RequiredVersion);
- }
-
using PowerShell pwsh = PowerShell.Create(this.Runspace);
- _ = pwsh.AddCommand(Commands.InstallModule)
- .AddParameters(parameters)
- .AddParameter(Parameters.Force)
- .Invoke();
-
+ this.powerShellGet.InstallModule(pwsh, moduleSpecification);
this.OnDiagnostics(DiagnosticLevel.Verbose, pwsh);
}
}
diff --git a/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/IProcessorEnvironment.cs b/src/Microsoft.Management.Configuration.Processor/ProcessorEnvironments/IProcessorEnvironment.cs
@@ -139,6 +139,13 @@ namespace Microsoft.Management.Configuration.Processor.ProcessorEnvironments
void SaveModule(PSObject inputObject, string location);
/// <summary>
+ /// Calls Save-Module.
+ /// </summary>
+ /// <param name="moduleSpecification">Module specification.</param>
+ /// <param name="location">Location to save module.</param>
+ void SaveModule(ModuleSpecification moduleSpecification, string location);
+
+ /// <summary>
/// Calls Install-Module -InputObject object.
/// Input object must be the result of Find cmdlets of PowerShellGet.
/// </summary>